1. 概述
本文将深入探讨 JUnit 5 引入的 @RepeatedTest 注解。它提供了一种简洁强大的方式,用于编写需要重复执行的测试用例。
⚠️ 如果你想了解更多 JUnit 5 基础知识,可以参考我们之前的文章:JUnit 5 基础教程 和 JUnit 5 完整指南。
2. Maven 依赖与环境配置
首先注意:JUnit 5 需要 Java 8 或更高版本。以下是核心 Maven 依赖:
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.10.2</version>
<scope>test</scope>
</dependency>
这是编写 JUnit 5 测试的必备依赖。最新版本可查看 Maven 中央仓库。
3. 简单的 @RepeatedTest 示例
创建重复测试非常简单粗暴——直接在测试方法上添加 @RepeatedTest 注解:
@RepeatedTest(3)
void repeatedTest(TestInfo testInfo) {
System.out.println("Executing repeated test");
assertEquals(2, Math.addExact(1, 1), "1 + 1 should equal 2");
}
✅ 关键点:
- 使用 @RepeatedTest 替代标准的 @Test 注解
- 上述测试将执行 3 次(相当于复制粘贴了 3 次相同测试)
测试报告(IDE 的 JUnit 标签页或报告文件)会显示所有执行记录:
repetition 1 of 3(repeatedTest(TestInfo))
repetition 2 of 3(repeatedTest(TestInfo))
repetition 3 of 3(repeatedTest(TestInfo))
4. 设置 failureThreshold
JUnit Jupiter 5.10 版本为 @RepeatedTest 新增了 failureThreshold 属性。它允许我们设定:当测试失败达到指定次数后,自动跳过剩余重复执行。
⚠️ 注意:
- 默认值为
Integer.MAX_VALUE
- failureThreshold 必须是正整数且小于重复次数
- 特别适用于偶尔因随机性或系统抖动导致失败的测试("踩坑"场景)
下面是一个测试随机数的示例,失败 2 次后终止执行:
@RepeatedTest(value = 10, failureThreshold = 2)
void whenGeneratingRandomNumber_thenNumberShouldBeWithinRange() {
int number = random.nextInt(10);
assertTrue(number < 8);
}
代码逻辑:
- 随机生成 0-9 的整数
- 断言数字必须小于 8
- 设置重复 10 次,失败阈值 2 次
💡 没有设置阈值时,任何一次失败都会导致整个测试失败。设置阈值后可以避免不必要的重复执行。
5. @RepeatedTest 的生命周期支持
每次 @RepeatedTest 执行都相当于独立 @Test,完整支持 JUnit 生命周期:
- @BeforeEach 和 @AfterEach 会在每次重复执行前后调用
添加生命周期方法验证:
@BeforeEach
void beforeEachTest() {
System.out.println("Before Each Test");
}
@AfterEach
void afterEachTest() {
System.out.println("After Each Test");
System.out.println("=====================");
}
运行测试后控制台输出:
Before Each Test
Executing repeated test
After Each Test
=====================
Before Each Test
Executing repeated test
After Each Test
=====================
Before Each Test
Executing repeated test
After Each Test
=====================
✅ 显然:**@BeforeEach 和 @AfterEach 在每次重复执行时都会被调用**
6. 配置测试名称
默认测试报告名称不够直观?通过 name 属性自定义:
使用内置命名模式
@RepeatedTest(value = 3, name = RepeatedTest.LONG_DISPLAY_NAME)
void repeatedTestWithLongName() {
System.out.println("Executing repeated test with long name");
assertEquals(2, Math.addExact(1, 1), "1 + 1 should equal 2");
}
输出:
repeatedTestWithLongName() :: repetition 1 of 3(repeatedTestWithLongName())
repeatedTestWithLongName() :: repetition 2 of 3(repeatedTestWithLongName())
repeatedTestWithLongName() :: repetition 3 of 3(repeatedTestWithLongName())
使用短名称模式
@RepeatedTest(value = 3, name = RepeatedTest.SHORT_DISPLAY_NAME)
void repeatedTestWithShortName() {
// 测试代码
}
输出:
repetition 1 of 3(repeatedTestWithShortName())
repetition 2 of 3(repeatedTestWithShortName())
repetition 3 of 3(repeatedTestWithShortName())
完全自定义名称
@RepeatedTest(value = 3, name = "Custom name {currentRepetition}/{totalRepetitions}")
void repeatedTestWithCustomDisplayName(TestInfo testInfo) {
assertEquals(2, Math.addExact(1, 1), "1 + 1 should equal 2");
}
输出:
Custom name 1/3(repeatedTestWithCustomDisplayName())
Custom name 2/3(repeatedTestWithCustomDisplayName())
Custom name 3/3(repeatedTestWithCustomDisplayName())
📌 占位符说明:
{currentRepetition}
:当前重复次数{totalRepetitions}
:总重复次数- JUnit 运行时自动填充,无需额外配置
7. 访问 RepetitionInfo
除了名称配置,JUnit 还允许在测试代码中获取重复元数据。只需在方法参数中添加 RepetitionInfo:
@RepeatedTest(3)
void repeatedTestWithRepetitionInfo(RepetitionInfo repetitionInfo) {
System.out.println("Repetition #" + repetitionInfo.getCurrentRepetition());
assertEquals(3, repetitionInfo.getTotalRepetitions());
}
控制台输出:
Repetition #1
Repetition #2
Repetition #3
⚠️ 注意:
- RepetitionInfo 由
RepetitionInfoParameterResolver
提供 - 仅在 @RepeatedTest 上下文中可用
8. 总结
本文系统介绍了 JUnit 5 的 @RepeatedTest 注解及其配置方式:
✅ 核心能力:
- 简单实现测试重复执行
- 灵活配置失败阈值避免无效执行
- 完整支持生命周期方法
- 可自定义测试报告名称
- 提供重复元数据访问接口
📖 完整源代码请访问 GitHub 仓库。