1. Overview
1.概述
When unit testing, we may, periodically, wish to process the results of our test method executions. In this quick tutorial, we’ll take a look at how we can accomplish this using the TestWatcher API provided by JUnit.
当单元测试时,我们可能会定期地希望处理我们的测试方法的执行结果。在这个快速教程中,我们将看看如何使用JUnit提供的TestWatcher API来实现这一目标。
For an in-depth guide to testing with JUnit, check out our excellent Guide to JUnit 5.
有关使用JUnit进行测试的深入指南,请查看我们优秀的JUnit 5指南。
2. The TestWatcher API
2、TestWatcher API
In short, the TestWatcher interface defines the API for extensions that wish to process test results. One way we can think of this API is providing hooks for getting the status of an individual test case.
简而言之,TestWatcher接口定义了希望处理测试结果的扩展程序的 API。我们可以认为这个API的一种方式是提供钩子来获取单个测试案例的状态。
But, before we dive into some real examples, let’s take a step back and briefly summarize the methods in the TestWatcher interface:
但是,在我们深入研究一些真实的例子之前,让我们退一步,简单地总结一下TestWatcher接口中的方法。
-
testAborted(ExtensionContext context, Throwable cause)
To process the results of an aborted test, we can override the testAborted method. As the name suggests, this method is invoked after a test has been aborted.
为了处理中止测试的结果,我们可以覆盖testAborted方法。顾名思义,这个方法是在测试被中止后调用的。
-
testDisabled(ExtensionContext context, Optional reason)
We can override the testDisabled method when we want to handle the results of a disabled test method. This method may also include the reason the test is disabled.
当我们想处理一个禁用的测试方法的结果时,我们可以覆盖testDisabled方法。这个方法也可以包括测试被禁用的原因。
-
testFailed(ExtensionContext context, Throwable cause)
If we want to do some additional processing after a test failure, we can simply implement the functionality in the testFailed method. This method may include the cause of the test failure.
如果我们想在测试失败后做一些额外的处理,我们可以简单地在testFailed方法中实现这些功能。这个方法可以包括测试失败的原因。
-
testSuccessful(ExtensionContext context)
Last but not least, when we wish to process the results of a successful test, we simply override the testSuccessful method.
最后但同样重要的是,当我们希望处理一个成功的测试结果时,我们只需覆盖testSuccessful方法。
We should note that all the methods contain the ExtensionContext. This encapsulates the context in which the current test executed.
我们应该注意,所有的方法都包含ExtensionContext。这封装了当前测试执行的上下文。
3. Maven Dependencies
3.Maven的依赖性
First of all, let’s add the project dependencies we will need for our examples.
Apart from the main JUnit 5 library junit-jupiter-engine, we’ll also need the junit-jupiter-api library:
首先,让我们添加我们的例子所需要的项目依赖。
除了主要的JUnit 5库junit-jupiter-engine之外,我们还需要junit-jupiter-api库。
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.8.1</version>
<scope>test</scope>
</dependency>
As always, we can get the latest version from Maven Central.
一如既往,我们可以从Maven中心获得最新版本。
4. A TestResultLoggerExtension Example
4.一个TestResultLoggerExtension例子
Now that we have a basic understanding of the TestWatcher API, we’ll walk through a practical example.
现在我们对TestWatcher API有了基本的了解,我们将通过一个实际的例子来进行探讨。
Let’s begin by creating a simple extension for logging the results and providing a summary of our tests. In this case, to create the extension, we need to define a class that implements the TestWatcher interface:
让我们首先创建一个简单的扩展,用于记录结果并提供测试的总结。在这种情况下,为了创建这个扩展,我们需要定义一个实现TestWatcher接口的类。
public class TestResultLoggerExtension implements TestWatcher, AfterAllCallback {
private List<TestResultStatus> testResultsStatus = new ArrayList<>();
private enum TestResultStatus {
SUCCESSFUL, ABORTED, FAILED, DISABLED;
}
//...
}
As with all extension interfaces, the TestWatcher interface also extends the main Extension interface, which is only a marker interface. In this example, we also implement the AfterAllCallback interface.
与所有的扩展接口一样,TestWatcher接口也扩展了主Extension接口,它只是一个标记接口。在这个例子中,我们也实现了AfterAllCallback接口。
In our extension, we have a list of TestResultStatus, which is a simple enumeration we’re going to use to represent the status of a test result.
在我们的扩展中,我们有一个TestResultStatus的列表,这是一个简单的枚举,我们将用来表示测试结果的状态。
4.1. Processing the Test Results
4.1.处理测试结果
Now, let’s see how to process the results of the individual unit test method:
现在,让我们看看如何处理各个单元测试方法的结果。
@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);
}
We begin by filling the body of our extension and overriding the testDisabled() and testSuccessful() methods.
我们首先填充扩展的主体,并覆盖testDisabled()和testSuccessful()方法。
In our trivial example, we output the name of the test and add the status of the test to the testResultsStatus list.
在我们这个微不足道的例子中,我们输出测试的名称,并将测试的状态添加到testResultsStatus列表中。
We’ll continue in this fashion for the other two methods — testAborted() and testFailed():
我们将继续以这种方式处理其他两个方法–testAborted()和testFailed():。
@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.2. Summarizing the Test Results
4.2.总结测试结果
In the last part of our example, we’ll override the afterAll() method:
在我们例子的最后部分,我们将覆盖afterAll()方法。
@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());
}
To quickly recap, the afterAll method is executed after all test methods have been run. We use this method to group the different TestResultStatus we have in the list of test results before outputting a very basic summary.
快速回顾一下,afterAll方法在所有测试方法运行后被执行。我们用这个方法将我们在测试结果列表中的不同TestResultStatus分组,然后输出一个非常基本的总结。
For an in-depth guide to Lifecycle Callbacks, check out our excellent Guide to JUnit 5 extensions.
有关生命周期回调的深入指南,请查看我们优秀的JUnit 5扩展指南。
5. Running the Tests
5.运行测试
In this penultimate section, we’ll see what the output from our tests looks like using our simple logging extension.
在这倒数第二节中,我们将看到使用我们的简单日志扩展的测试输出是什么样子。
Now that we’ve defined our extension, we’ll first register it using the standard @ExtendWith annotation:
现在我们已经定义了我们的扩展,我们将首先使用标准的@ExtendWith注解来注册它。
@ExtendWith(TestResultLoggerExtension.class)
class TestWatcherAPIUnitTest {
@Test
void givenFalseIsTrue_whenTestAbortedThenCaptureResult() {
Assumptions.assumeTrue(false);
}
@Disabled
@Test
void givenTrueIsTrue_whenTestDisabledThenCaptureResult() {
Assert.assertTrue(true);
}
//...
Next, we fill our test class with unit tests, adding a mixture of disabled, aborted, and successful tests.
接下来,我们用单元测试填充我们的测试类,添加禁用、中止和成功测试的混合物。
5.1. Reviewing the Output
5.1.审查输出
When we run the unit test, we should see the output for each test:
当我们运行单元测试时,我们应该看到每个测试的输出。
INFO c.b.e.t.TestResultLoggerExtension -
Test Successful for test givenTrueIsTrue_whenTestAbortedThenCaptureResult()
...
Test result summary for TestWatcherAPIUnitTest {ABORTED=1, SUCCESSFUL=1, DISABLED=2}
Naturally, we’ll also see the summary printed when all the test methods have completed.
自然地,当所有的测试方法都完成后,我们也会看到打印的摘要。
6. Gotchas
6.Gotchas
In this last section, let’s review a couple of the subtleties we should be aware of when working with the TestWatcher interface:
在最后一节,让我们回顾一下在使用TestWatcher接口时应该注意的几个细微之处。
- TestWatcher extensions are not permitted to influence the execution of tests; this means if an exception is thrown from a TestWatcher, it will not be propagated up to the running test
- Currently, this API is only used to report the results of @Test methods and @TestTemplate methods
- By default, if no reason is provided to the testDisabled method, then it will contain the fully qualified name of the test method followed by ‘is @Disabled‘
7. Conclusion
7.结论
To summarize, in this tutorial, we’ve shown how we can make use of the JUnit 5 TestWatcher API to process the results of our test method executions.
总之,在本教程中,我们展示了如何利用JUnit 5 TestWatcher API来处理测试方法的执行结果。
The full source code of the examples can be found over on GitHub.
示例的完整源代码可以在GitHub上找到。