1. 概述

在 Java 项目中使用 TestNG 时,高效管理测试的初始化和清理操作是构建清晰、隔离且可维护测试的关键。两个常用注解 @BeforeTest@BeforeMethod 通过在测试生命周期的不同阶段执行初始化代码来实现这一目标

理解这两个注解的区别并掌握各自适用场景,能显著提升测试用例的组织性和执行效率。

本文将深入探讨这些注解,分析其核心差异,并说明不同场景下的最佳实践。

2. Maven 依赖

在深入注解之前,确保已在 Maven 项目的 pom.xml 中添加 TestNG 依赖:

<dependency>
    <groupId>org.testng</groupId>
    <artifactId>testng</artifactId>
    <version>7.10.2</version>
    <scope>test</scope>
</dependency>

3. 理解 @BeforeTest

@BeforeTest 注解会在测试类中所有带 @Test 的方法执行前运行一次*。

当测试类包含多个测试方法时,该注解非常适合初始化共享资源,例如:

  • 初始化应用上下文
  • 创建共享对象实例
  • 建立数据库连接

先看一个示例。首先创建一个 Counter 类:

public class Counter {
    private int totalCount;

    public Counter(int totalCount) {
        this.totalCount = totalCount;
    }

    public int getTotalCount() {
        return totalCount;
    }

    public void addCounter(int number) {
        this.totalCount = totalCount + number;
    }

    public void subtractCounter(int number) {
        this.totalCount = totalCount - number;
    }

    public void resetTotalCount() {
        this.totalCount = 0;
    }
}

现在创建测试类 BeforeTestAnnotationTest

public class BeforeTestAnnotationTest {
    private static final Logger log = LoggerFactory.getLogger(BeforeTestAnnotationTest.class);

    Counter counter;

    @BeforeTest
    public void init() {
        log.info("Initializing ...");
        counter = new Counter(0);
    }

    @Test
    public void givenCounterInitialized_whenAddingValue_thenTotalCountIncreased() {
        log.info("total counter before added: {}", counter.getTotalCount());
        counter.addCounter(2);
        log.info("total counter after added: {}", counter.getTotalCount());
    }

    @Test
    public void givenCounterInitialized_whenSubtractingValue_thenTotalCountDecreased() {
        log.info("total counter before subtracted: {}", counter.getTotalCount());
        counter.subtractCounter(1);
        log.info("total counter after subtracted: {}", counter.getTotalCount());
    }
}

执行测试后输出:

Initializing ...
total counter before added: 0
total counter after added: 2
total counter before subtracted: 2
total counter after subtracted: 1

关键执行流程:

  • givenCounterInitialized_whenAddingValue_thenTotalCountIncreased() 执行时,totalCount 初始值为 @BeforeTest 设置的 0
  • ⚠️ givenCounterInitialized_whenSubtractingValue_thenTotalCountDecreased() 执行时,直接使用前一个测试修改后的值(2),而非重新初始化的 0

4. 理解 @BeforeMethod

@BeforeMethod 注解会在测试类中每个 @Test 方法执行前运行*。

适用于需要为每个测试重置或重新初始化的任务,例如:

  • 重置变量状态
  • 清理测试数据
  • 创建隔离的测试环境

这能确保每个测试独立运行,避免测试间相互影响。

下面用 @BeforeMethod 重置 counter 对象的 totalCount 值。创建测试类 BeforeMethodAnnotationTest

public class BeforeMethodAnnotationTest {
    private static final Logger log = LoggerFactory.getLogger(BeforeMethodAnnotationTest.class);

    Counter counter;

    @BeforeTest
    public void init() {
        log.info("Initializing ...");
        counter = new Counter(0);
    }

    @BeforeMethod
    public void givenCounterInitialized_whenResetTotalCount_thenTotalCountValueReset() {
        log.info("resetting total counter value ...");
        counter.resetTotalCount();
    }

    @Test
    public void givenCounterInitialized_whenAddingValue_thenTotalCountIncreased() {
        log.info("total counter before added: {}", counter.getTotalCount());
        counter.addCounter(2);
        log.info("total counter after added: {}", counter.getTotalCount());
    }

    @Test
    public void givenCounterInitialized_whenSubtractingValue_thenTotalCountDecreased() {
        log.info("total counter before subtracted: {}", counter.getTotalCount());
        counter.subtractCounter(2);
        log.info("total counter after subtracted: {}", counter.getTotalCount());
    }
}

执行测试后输出:

Initializing ...
resetting total counter value ...
total counter before added: 0
total counter after added: 2
resetting total counter value ...
total counter before subtracted: 0
total counter after subtracted: -2

关键执行流程:

  • @BeforeTestinit() 方法在所有测试前执行一次,初始化 counter
  • @BeforeMethodreset() 方法在每个测试前执行,确保 totalCount 重置为 0
  • ✅ 每个测试方法开始时 totalCount 始终为 0,实现测试间完全隔离

5. 核心差异对比

方面 @BeforeTest @BeforeMethod
执行范围 整个测试类仅执行一次 每个测试方法前都执行
适用场景 初始化共享资源 重置测试状态/创建隔离环境
典型用法 建立数据库连接
初始化应用上下文
清理测试数据
重置对象状态

6. 选择注解的实用指南

根据实际需求选择合适的注解:

  • 使用 @BeforeTest 的场景

    • 需要跨多个测试共享配置
    • 初始化重量级资源(如数据库连接池)
    • 创建应用上下文或全局配置对象
  • 使用 @BeforeMethod 的场景

    • 需要确保测试间完全隔离
    • 重置可变状态(如计数器、缓存)
    • 清理测试产生的临时数据

⚠️ 踩坑提示:错误使用 @BeforeTest 可能导致测试间数据污染,而滥用 @BeforeMethod 则可能影响测试执行效率。

7. 总结

在 TestNG 中,*@BeforeTest* 和 @BeforeMethod 为组织 Java 测试套件提供了强大工具。理解其核心差异后:

  • @BeforeTest 处理仅需执行一次的共享配置
  • @BeforeMethod 确保每个测试的独立性和隔离性

这种分层初始化策略能显著提升复杂测试环境(如 Spring 应用)的可靠性和可维护性。代码示例已在 GitHub 开源。


原始标题:Difference Between BeforeTest and BeforeMethod in TestNG | Baeldung