第2章 JUnit5基础注解:@Test、@BeforeEach、@AfterEach、@BeforeAll、@AfterAll、@DisplayName、@Disabled

目标:掌握 JUnit5 最核心的生命周期注解与显示控制注解,能够独立编写可重复、可读性强的测试用例。

2.1 原理概述

JUnit5(Jupiter)将测试生命周期划分为 类级别 和 方法级别 两个维度,通过注解声明执行时机。下表列出本章涉及的 7 个基础注解及其作用域:

注解 作用域 执行时机 典型用途
@Test 方法 每执行一个测试方法时 标记一个测试用例
@BeforeEach 方法 每个 @Test 前执行 初始化测试对象、重置状态
@AfterEach 方法 每个 @Test 后执行 清理资源(关闭文件、释放连接)
@BeforeAll 静态方法 所有测试之前,仅一次 建立数据库连接、加载配置
@AfterAll 静态方法 所有测试之后,仅一次 关闭全局资源
@DisplayName 类/方法 无执行语义 为测试类或方法提供可读名称
@Disabled 类/方法 被禁用的测试不执行 跳过暂时失败的测试

2.2 执行流程与SVG图解

对于一个包含 2 个 @Test 方法的测试类,完整的生命周期执行顺序如下:

  1. @BeforeAll(静态方法,执行一次)
  2. 循环执行每个测试方法:@BeforeEach → @Test → @AfterEach
  3. @AfterAll(静态方法,执行一次)
JUnit5 生命周期注解执行顺序 @BeforeAll @BeforeEach @Test @AfterEach @AfterAll 第二个 @Test 重复流程 虚线箭头:循环至下一个 @Test
关键点:@BeforeAll 和 @AfterAll 必须声明为 static,否则运行时会抛出 org.junit.jupiter.api.extension.ExtensionConfigurationException。

2.3 完整代码示例

以下示例演示了所有注解的使用方式,并包含 @DisplayName 和 @Disabled:

import org.junit.jupiter.api.*;

import static org.junit.jupiter.api.Assertions.assertEquals;

@DisplayName("计算器测试套件")
public class CalculatorTest {

    private Calculator calculator;

    @BeforeAll
    static void initAll() {
        System.out.println("=== 全局初始化:加载配置 ===");
    }

    @BeforeEach
    void init() {
        calculator = new Calculator();
        System.out.println("  新计算器实例已创建");
    }

    @Test
    @DisplayName("加法测试:正数相加")
    void testAddPositive() {
        int result = calculator.add(3, 5);
        assertEquals(8, result, "3 + 5 应等于 8");
    }

    @Test
    @DisplayName("减法测试:正数相减")
    void testSubtract() {
        int result = calculator.subtract(10, 4);
        assertEquals(6, result, "10 - 4 应等于 6");
    }

    @Test
    @Disabled("因需求变更暂时跳过,待修复后启用")
    @DisplayName("乘法测试(禁用)")
    void testMultiplyDisabled() {
        int result = calculator.multiply(2, 3);
        assertEquals(6, result);
    }

    @AfterEach
    void tearDown() {
        System.out.println("  清理单个测试资源");
    }

    @AfterAll
    static void tearDownAll() {
        System.out.println("=== 全局清理:关闭连接 ===");
    }
}

2.4 执行结果观察

运行上述测试,控制台输出顺序如下(在每个 @Test 前 @BeforeEach 都会执行):

=== 全局初始化:加载配置 ===
  新计算器实例已创建
  清理单个测试资源
  新计算器实例已创建
  清理单个测试资源
=== 全局清理:关闭连接 ===

被 @Disabled 标记的测试方法不会出现在输出中,IDE 中会显示为“跳过”。

2.5 调试与常见错误

常见错误 原因 解决方案
BeforeAll 方法非静态 Jupiter 要求 @BeforeAll/@AfterAll 为静态方法 添加 static 关键字
@Test 返回非 void JUnit5 不允许测试方法有返回值 将返回类型改为 void
@DisplayName 未生效 使用了旧 IDE 版本或未添加JUnit5依赖 确认依赖为 org.junit.jupiter 而非 junit4
资源泄漏在 @AfterEach 未处理 每个测试后未彻底清理 在 @AfterEach 中显式关闭打开的资源

2.6 性能与稳定性提示

避免耗时操作在 @BeforeEach 中重复执行:如果初始化逻辑耗时较长(如创建大型对象或建立网络连接),应将其移至 @BeforeAll。若每个测试必须独立状态,可考虑使用 @TestInstance(Lifecycle.PER_CLASS) 减少重复创建开销。
  • 使用 @Disabled 管理不稳定测试,避免 CI 流水线中断,但应定期修复并移除该注解。
  • 为测试类和方法添加 @DisplayName,提高测试报告可读性,方便非技术人员审查。
  • @AfterEach 中清理资源时,始终使用 try-finally 或断言失败时的回滚机制,防止状态污染后续测试。

2.7 小结