第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 方法的测试类,完整的生命周期执行顺序如下:
@BeforeAll(静态方法,执行一次)- 循环执行每个测试方法:
@BeforeEach→@Test→@AfterEach @AfterAll(静态方法,执行一次)
关键点:
@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 或断言失败时的回滚机制,防止状态污染后续测试。