一、自定义 Rule
1、Custom Rule
java
public class CustomTestRule implements TestRule {
@Override
public Statement apply(Statement base, Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
// 测试执行前
beforeTest(description);
try {
// 测试执行
base.evaluate();
// 测试成功
onTestSuccess(description);
} catch (Throwable t) {
// 测试失败
onTestFailure(description, t);
throw t;
} finally {
// 无论测试成功失败
afterTest(description);
}
}
};
}
private void beforeTest(Description description) {
System.out.println("开始测试: " + description.getMethodName());
}
private void onTestSuccess(Description description) {
System.out.println("测试通过: " + description.getMethodName());
}
private void onTestFailure(Description description, Throwable t) {
System.out.println("测试失败: " + description.getMethodName() + " - " + t.getMessage());
}
private void afterTest(Description description) {
System.out.println("测试结束: " + description.getMethodName());
}
}
2、Test
java
public class CustomTestRuleTest {
@Rule
public CustomTestRule customTestRule = new CustomTestRule();
@Test
public void test() {
System.out.println("执行测试逻辑...");
}
}
# 输出结果
开始测试: test
执行测试逻辑...
测试通过: test
测试结束: test
二、实例实操(重试 Rule)
1、Custom Rule
java
public class RetryRule implements TestRule {
private final int maxRetries;
public RetryRule(int maxRetries) {
this.maxRetries = maxRetries;
}
@Override
public Statement apply(Statement base, Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
for (int attempt = 1; attempt <= maxRetries; attempt++) {
try {
System.out.printf("第 %d / %d 次尝试执行测试: %s%n", attempt, maxRetries, description.getMethodName());
base.evaluate();
System.out.printf("第 %d 次执行测试成功%n", attempt);
return;
} catch (Throwable e) {
System.err.printf("第 %d 次执行测试失败: %s%n", attempt, e.getMessage());
if (attempt < maxRetries) {
waitBeforeRetry(attempt);
continue;
}
throw e; // 超过最大重试次数,抛出异常
}
}
}
};
}
private void waitBeforeRetry(int attempt) throws InterruptedException {
// 指数退避策略
long waitTime = Math.min(1000 * (long) Math.pow(2, attempt - 1), 10000);
System.out.printf("等待 %dms 后重试...%n", waitTime);
Thread.sleep(waitTime);
}
}
2、Test
java
public class RetryRuleTest {
@Rule
public RetryRule retryRule = new RetryRule(3);
@Test
public void test() {
System.out.println("执行测试逻辑...");
}
}
# 输出结果
第 1 / 3 次尝试执行测试: test
执行测试逻辑...
第 1 次执行测试成功
java
public class RetryRuleTest {
@Rule
public RetryRule retryRule = new RetryRule(3);
@Test
public void test() {
int a = 10 / 0;
}
}
# 输出结果
第 1 / 3 次尝试执行测试: test
第 1 次执行测试失败: / by zero
等待 1000ms 后重试...
第 2 / 3 次尝试执行测试: test
第 2 次执行测试失败: / by zero
等待 2000ms 后重试...
第 3 / 3 次尝试执行测试: test
第 3 次执行测试失败: / by zero
三、关于异常重新抛出
java
public class CustomTestRule implements TestRule {
@Override
public Statement apply(Statement base, Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
beforeTest(description);
try {
base.evaluate();
onTestSuccess(description);
} catch (Throwable t) {
onTestFailure(description, t);
// 异常重新抛出
throw t;
} finally {
afterTest(description);
}
}
};
}
private void beforeTest(Description description) {
System.out.println("开始测试: " + description.getMethodName());
}
private void onTestSuccess(Description description) {
System.out.println("测试通过: " + description.getMethodName());
}
private void onTestFailure(Description description, Throwable t) {
System.out.println("测试失败: " + description.getMethodName() + " - " + t.getMessage());
}
private void afterTest(Description description) {
System.out.println("测试结束: " + description.getMethodName());
}
}
-
异常重新抛出确保了失败信息能传递到 JUnit 框架,如果不抛出,即使测试方法失败了,也会显示为成功状态
-
TestRule 只是增强测试,而不是替代测试框架的错误处理
-
异常重新抛出保持测试的原始语义,只是在执行前后添加了额外的逻辑