1. 概述

在进行单元测试时,我们常常需要对测试方法的执行结果进行处理或记录。本文将深入讲解如何使用 JUnit 5 提供的 TestWatcher API 来实现这一需求。

如果你对 JUnit 5 测试机制还不熟悉,建议先阅读我们的 JUnit 5 使用指南

2. TestWatcher API 简介

JUnit 5 的 TestWatcher 接口提供了一种扩展机制,允许我们在测试方法执行后捕获其执行结果。你可以把它理解为一个“监听器”,用于监听测试用例的状态变化。

它定义了以下几个关键方法:

testDisabled(ExtensionContext context, Optional<String> reason)
测试被禁用时触发,可获取禁用原因。

testSuccessful(ExtensionContext context)
测试成功时触发。

testAborted(ExtensionContext context, Throwable cause)
测试被中止时触发(比如因为前置条件不满足而跳过)。

testFailed(ExtensionContext context, Throwable cause)
测试失败时触发,可获取异常信息。

⚠️ 所有方法都提供了一个 ExtensionContext 参数,可用于获取测试执行的上下文信息,比如测试类名、方法名等。

3. Maven 依赖配置

要使用 TestWatcher,你需要引入 JUnit Jupiter API 模块:

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-api</artifactId>
    <version>5.10.2</version>
    <scope>test</scope>
</dependency>

此外,别忘了引入 JUnit Jupiter Engine:

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-engine</artifactId>
    <version>5.10.2</version>
    <scope>test</scope>
</dependency>

最新版本可在 Maven Central 获取。

4. 示例:实现 TestResultLoggerExtension

下面我们实现一个简单的测试结果记录器,用于记录每个测试用例的状态并在所有测试执行完成后输出汇总信息。

4.1. 定义 Extension

public class TestResultLoggerExtension implements TestWatcher, AfterAllCallback {
    private List<TestResultStatus> testResultsStatus = new ArrayList<>();

    private enum TestResultStatus {
        SUCCESSFUL, ABORTED, FAILED, DISABLED;
    }

    // 实现 TestWatcher 的四个方法
    // 实现 AfterAllCallback 的 afterAll 方法
}

这个类实现了 TestWatcher 接口,同时实现了 AfterAllCallback 接口,以便在所有测试执行完成后输出汇总结果。

4.2. 处理测试结果

我们依次实现四个方法,记录测试状态到 testResultsStatus 列表中:

@Override
public void testDisabled(ExtensionContext context, Optional<String> reason) {
    LOG.info("Test Disabled for test {}: with reason :- {}", 
      context.getDisplayName(),
      reason.orElse("No reason"));

    testResultsStatus.add(TestResultStatus.DISABLED);
}

@Override
public void testSuccessful(ExtensionContext context) {
    LOG.info("Test Successful for test {}: ", context.getDisplayName());
    testResultsStatus.add(TestResultStatus.SUCCESSFUL);
}

@Override
public void testAborted(ExtensionContext context, Throwable cause) {
    LOG.info("Test Aborted for test {}: ", context.getDisplayName());
    testResultsStatus.add(TestResultStatus.ABORTED);
}

@Override
public void testFailed(ExtensionContext context, Throwable cause) {
    LOG.info("Test Failed for test {}: ", context.getDisplayName());
    testResultsStatus.add(TestResultStatus.FAILED);
}

4.3. 输出测试汇总

在所有测试执行完毕后,我们输出一个简单的汇总信息:

@Override
public void afterAll(ExtensionContext context) throws Exception {
    Map<TestResultStatus, Long> summary = testResultsStatus.stream()
      .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

    LOG.info("Test result summary for {} {}", context.getDisplayName(), summary.toString());
}

这部分逻辑使用 Java Stream API 对测试结果进行分组统计,并打印出每个状态的测试数量。

5. 使用测试类注册 Extension

要在测试类中使用该扩展,只需加上 @ExtendWith 注解:

@ExtendWith(TestResultLoggerExtension.class)
class TestWatcherAPIUnitTest {

    @Test
    void givenFalseIsTrue_whenTestAbortedThenCaptureResult() {
        Assumptions.assumeTrue(false);
    }

    @Disabled
    @Test
    void givenTrueIsTrue_whenTestDisabledThenCaptureResult() {
        Assert.assertTrue(true);
    }

    @Test
    void givenTrueIsTrue_whenTestSuccessfulThenCaptureResult() {
        Assert.assertTrue(true);
    }

    @Test
    void givenFalseIsTrue_whenTestFailedThenCaptureResult() {
        Assert.assertTrue(false);
    }
}

这个测试类包含了四种状态的测试:成功、失败、禁用、中止。

6. 输出结果示例

运行测试后,控制台将输出如下日志:

INFO  c.b.e.t.TestResultLoggerExtension - 
    Test Successful for test givenTrueIsTrue_whenTestAbortedThenCaptureResult()
...
Test result summary for TestWatcherAPIUnitTest {ABORTED=1, SUCCESSFUL=1, DISABLED=2}

这说明我们成功记录了每个测试的状态,并在最后输出了汇总结果。

7. 使用时的注意事项

使用 TestWatcher 时需要注意以下几点:

TestWatcher 扩展不能影响测试执行流程。如果在监听器中抛出异常,该异常不会传递到测试方法中。

✅ 当前 TestWatcher 只支持 @Test@TestTemplate 方法。

✅ 如果未提供禁用原因,testDisabled() 方法会默认使用“测试方法全限定名 + is @Disabled”的格式。

8. 总结

通过本文,我们了解了 JUnit 5 的 TestWatcher API 的作用,并实现了一个简单的测试结果记录器。你可以基于这个机制扩展出更强大的功能,比如生成 HTML 报告、发送邮件通知、集成 CI/CD 等。

完整示例代码可在 GitHub 仓库 获取。



原始标题:JUnit 5 TestWatcher API