一、重复测试是什么?
重复测试通过 @RepeatedTest
注解标记一个测试方法,使其重复执行多次,每次执行被视为独立的测试用例。它适用于验证代码的稳定性、随机性行为或性能基准测试。
核心特点:
- 多次独立执行:每次重复作为独立测试,失败不影响其他执行。
- 动态显示名称:支持自定义测试名称,包含当前重复次数。
- 生命周期支持:每次重复均触发
@BeforeEach
和@AfterEach
方法。
二、核心注解与参数
注解/参数 | 说明 |
---|---|
@RepeatedTest(n) | 标记方法为重复测试,n 指定重复次数。 |
RepetitionInfo | 注入参数,提供当前重复次数(currentRepetition )和总次数(totalRepetitions )。 |
name 属性 | 自定义测试名称,支持占位符 {currentRepetition} 和 {totalRepetitions} 。 |
三、使用场景
- 稳定性验证
确保代码在多次执行中不出现偶发错误。 - 随机数据测试
测试随机生成的数据是否符合预期分布。 - 性能基准测试
重复执行以计算平均耗时(需结合时间测量工具)。 - 边界条件压力测试
多次验证边界条件下的代码行为。
四、基础示例
示例 1:简单重复测试
import org.junit.jupiter.api.*;
class RepeatedTestDemo {
@RepeatedTest(3)
void basicRepeatedTest() {
Assertions.assertTrue(Math.random() >= 0);
}
}
执行结果:
√ basicRepeatedTest() - 重复 1/3
√ basicRepeatedTest() - 重复 2/3
√ basicRepeatedTest() - 重复 3/3
示例 2:自定义显示名称
@RepeatedTest(
value = 3,
name = "第 {currentRepetition} 次测试,共 {totalRepetitions} 次"
)
void customNameRepeatedTest() {
Assertions.assertNotEquals(0, System.currentTimeMillis());
}
执行结果:
√ 第 1 次测试,共 3 次
√ 第 2 次测试,共 3 次
√ 第 3 次测试,共 3 次
五、访问重复上下文
通过 RepetitionInfo
参数获取当前重复信息:
@RepeatedTest(5)
void testWithRepetitionInfo(RepetitionInfo info) {
int current = info.getCurrentRepetition();
int total = info.getTotalRepetitions();
System.out.printf("执行 %d/%d%n", current, total);
Assertions.assertTrue(current <= total);
}
六、结合生命周期方法
每次重复均会触发 @BeforeEach
和 @AfterEach
方法:
@BeforeEach
void setup() {
System.out.println("初始化资源...");
}
@AfterEach
void cleanup() {
System.out.println("清理资源...");
}
@RepeatedTest(2)
void testWithLifecycle() {
System.out.println("执行测试逻辑");
}
执行结果:
初始化资源...
执行测试逻辑
清理资源...
初始化资源...
执行测试逻辑
清理资源...
七、高级应用场景
场景 1:随机性测试
验证随机数生成在多次执行中不越界:
@RepeatedTest(100)
void testRandomNumberInRange() {
double random = Math.random();
Assertions.assertTrue(random >= 0 && random < 1);
}
场景 2:性能基准测试(伪代码)
重复执行以测量平均耗时:
@RepeatedTest(100)
void measurePerformance() {
long start = System.nanoTime();
// 执行被测逻辑
long duration = System.nanoTime() - start;
Assertions.assertTrue(duration < 1_000_000, "执行时间超过 1ms");
}
八、注意事项
- 独立性
每次重复是独立的测试用例,共享类实例但测试方法状态独立。 - 生命周期方法
@BeforeAll
和@AfterAll
在整个测试类生命周期中仅执行一次。 - 性能开销
避免无意义的大量重复,尤其是涉及 I/O 或复杂计算的测试。
九、重复测试 vs 参数化测试
特性 | 重复测试(@RepeatedTest ) | 参数化测试(@ParameterizedTest ) |
---|---|---|
目的 | 相同逻辑多次执行 | 不同参数多次执行相同逻辑 |
输入变化 | 无(相同输入重复执行) | 每次执行使用不同输入参数 |
适用场景 | 稳定性、随机性、性能测试 | 多数据组合验证 |
十、总结
何时使用重复测试:
- 验证代码在多次执行中的稳定性。
- 测试依赖随机数或时间戳的逻辑。
- 需要重复执行以捕获偶发性问题。
通过合理配置重复次数和结合 RepetitionInfo
,重复测试能有效提升测试覆盖率和可靠性。对于需要不同输入参数的场景,应优先选择参数化测试。