The Spring TestExecutionListener – Spring的TestExecutionListener

最后修改: 2019年 10月 19日

中文/混合/英文(键盘快捷键:t)

 1. Overview

1.概述

Typically, we use the JUnit annotations like @BeforeEach, @AfterEach, @BeforeAll, and @AfterAll, to orchestrate tests’ lifecycle, but sometimes that’s not enough — especially when we’re working with the Spring framework.

通常,我们使用JUnit注解,如@BeforeEach, @AfterEach, @BeforeAll,@AfterAll,来协调测试的生命周期,但有时这还不够–特别是当我们与Spring框架合作时。

This is where Spring TestExecutionListener comes in handy.

这就是Spring TestExecutionListener的用武之地。

In this tutorial, we’ll see what the TestExecutionListener offers, the default listeners provided by Spring, and how to implement a custom TestExecutionListener.

在本教程中,我们将看到TestExecutionListener提供的内容、Spring提供的默认监听器,以及如何实现一个自定义的TestExecutionListener

2. The TestExecutionListener Interface

2.TestExecutionListener 接口

First, let’s visit the TestExecutionListener interface:

首先,让我们访问TestExecutionListener接口。

public interface TestExecutionListener {
    default void beforeTestClass(TestContext testContext) throws Exception {};
    default void prepareTestInstance(TestContext testContext) throws Exception {};
    default void beforeTestMethod(TestContext testContext) throws Exception {};
    default void afterTestMethod(TestContext testContext) throws Exception {};
    default void afterTestClass(TestContext testContext) throws Exception {};
}

The implementations of this interface can receive events during different test execution stages. Consequently, each of the methods in the interface is passed a TestContext object.

这个接口的实现可以在不同的测试执行阶段接收事件。因此,该接口中的每个方法都要传递一个TestContext对象。

This TestContext object contains information of the Spring context and of the target test class and methods. This information can be used to alter the behavior of the tests or to extend their functionality.

这个TestContext对象包含Spring上下文以及目标测试类和方法的信息。这些信息可以用来改变测试的行为或扩展其功能。

Now, let’s take a quick look at each of these methods:

现在,让我们快速看一下这些方法中的每一个。

  • afterTestClass – post-processes a test class after the execution of all tests within the class
  • afterTestExecution – post-processes a test immediately after execution of the test method in the supplied test context
  • afterTestMethod – post-processes a test after execution of after-lifecycle callbacks of the underlying test framework
  • beforeTestClass – pre-processes a test class before execution of all tests within the class
  • beforeTestExecution – pre-processes a test immediately before execution of the test method in the supplied test context
  • beforeTestMethod – pre-processes a test before execution of before-lifecycle callbacks of the underlying test framework
  • prepareTestInstance – prepares the test instance of the supplied test context

It’s worth noting that this interface provides empty default implementations for all the methods. Consequently, concrete implementations can choose to override only those methods that are suitable for the task at hand.

值得注意的是,这个接口为所有的方法提供了空的默认实现。因此,具体实现可以选择只覆盖那些适合手头工作的方法。

3. Spring’s Default TestExecutionListeners

3.Spring的默认TestExecutionListeners

By default, Spring provides some TestExecutionListener implementations out-of-the-box.

默认情况下,Spring提供了一些开箱即用的TestExecutionListener实现。

Let’s quickly look at each of these:

让我们快速地看一下每一项。

  • ServletTestExecutionListener – configures Servlet API mocks for a WebApplicationContext
  • DirtiesContextBeforeModesTestExecutionListener – handles the @DirtiesContext annotation for “before” modes
  • DependencyInjectionTestExecutionListener – provides dependency injection for the test instance
  • DirtiesContextTestExecutionListener – handles the @DirtiesContext annotation for “after” modes
  • TransactionalTestExecutionListener – provides transactional test execution with default rollback semantics
  • SqlScriptsTestExecutionListener – runs SQL scripts configured using the @Sql annotation

These listeners are pre-registered exactly in the order listed. We’ll see more about the order when we create a custom TestExecutionListener.

这些监听器是完全按照列出的顺序预注册的。当我们创建一个自定义的TestExecutionListener时,我们会看到更多关于这个顺序的信息。

4. Using a Custom TestExecutionListener

4.使用一个自定义的TestExecutionListener

Now, let’s define a custom TestExecutionListener:

现在,让我们定义一个自定义的TestExecutionListener

public class CustomTestExecutionListener implements TestExecutionListener, Ordered {
    private static final Logger logger = LoggerFactory.getLogger(CustomTestExecutionListener.class);
    
    public void beforeTestClass(TestContext testContext) throws Exception {
        logger.info("beforeTestClass : {}", testContext.getTestClass());
    }; 
    
    public void prepareTestInstance(TestContext testContext) throws Exception {
        logger.info("prepareTestInstance : {}", testContext.getTestClass());
    }; 
    
    public void beforeTestMethod(TestContext testContext) throws Exception {
        logger.info("beforeTestMethod : {}", testContext.getTestMethod());
    }; 
    
    public void afterTestMethod(TestContext testContext) throws Exception {
        logger.info("afterTestMethod : {}", testContext.getTestMethod());
    }; 
    
    public void afterTestClass(TestContext testContext) throws Exception {
        logger.info("afterTestClass : {}", testContext.getTestClass());
    }

    @Override
    public int getOrder() {
        return Integer.MAX_VALUE;
    };
}

For simplicity, all this class does is log some of the TestContext information.

为了简单起见,这个类所做的只是记录一些TestContext信息。

4.1. Registering the Custom Listener Using @TestExecutionListeners

4.1.使用@TestExecutionListeners注册自定义监听器

Now, let’s use this listener in our test class. To do this, we’ll register it by using the @TestExecutionListeners annotation:

现在,让我们在我们的测试类中使用这个监听器。要做到这一点,我们将通过使用@TestExecutionListeners注解来注册它。

@RunWith(SpringRunner.class)
@TestExecutionListeners(value = {
  CustomTestExecutionListener.class,
  DependencyInjectionTestExecutionListener.class
})
@ContextConfiguration(classes = AdditionService.class)
public class AdditionServiceUnitTest {
    // ...
}

It’s important to note that using the annotation will de-register all default listeners. Hence, we’ve added DependencyInjectionTestExecutionListener explicitly so that we can use auto wiring in our test class.

值得注意的是,使用注解将取消所有默认监听器的注册。因此,我们明确地添加了DependencyInjectionTestExecutionListener,这样我们就可以在测试类中使用自动布线。

If we need any of the other default listeners, we’ll have to specify each of them. But, we can also use the mergeMode property of the annotation:

如果我们需要任何其他的默认监听器,我们就必须指定每一个。但是,我们也可以使用注解的mergeMode属性。

@TestExecutionListeners(
  value = { CustomTestExecutionListener.class }, 
  mergeMode = MergeMode.MERGE_WITH_DEFAULTS)

Here, MERGE_WITH_DEFAULTS indicates that the locally declared listeners should be merged with the default listeners.

这里,MERGE_WITH_DEFAULTS表示本地声明的监听器应该与默认监听器合并。

Now, when we run the above test, the listener will log each event it receives:

现在,当我们运行上述测试时,监听器将记录它收到的每个事件。

[main] INFO  o.s.t.c.s.DefaultTestContextBootstrapper - Using TestExecutionListeners: 
[com.baeldung.testexecutionlisteners.CustomTestExecutionListener@38364841, 
org.springframework.test.context.support.DependencyInjectionTestExecutionListener@28c4711c]
[main] INFO  c.b.t.CustomTestExecutionListener - beforeTestClass : 
class com.baeldung.testexecutionlisteners.TestExecutionListenersWithoutMergeModeUnitTest
[main] INFO  c.b.t.CustomTestExecutionListener - prepareTestInstance : 
class com.baeldung.testexecutionlisteners.TestExecutionListenersWithoutMergeModeUnitTest
[main] INFO  o.s.c.s.GenericApplicationContext - 
Refreshing org.springframework.context.support.GenericApplicationContext@7d68ef40: startup date [XXX]; 
root of context hierarchy
[main] INFO  c.b.t.CustomTestExecutionListener - beforeTestMethod : 
public void com.baeldung.testexecutionlisteners.TestExecutionListenersWithoutMergeModeUnitTest
.whenValidNumbersPassed_thenReturnSum()
[main] INFO  c.b.t.CustomTestExecutionListener - afterTestMethod : 
public void com.baeldung.testexecutionlisteners.TestExecutionListenersWithoutMergeModeUnitTest
.whenValidNumbersPassed_thenReturnSum()
[main] INFO  c.b.t.CustomTestExecutionListener - afterTestClass : 
class com.baeldung.testexecutionlisteners.TestExecutionListenersWithoutMergeModeUnitTest

4.2. Automatic Discovery of Default TestExecutionListener Implementations

4.2.自动发现默认的TestExecutionListener实现

Using @TestExecutionListener to register listeners is suitable if it’s used in a limited number of test classes. But, it can become cumbersome to add it to an entire test suite.

如果在有限的测试类中使用@TestExecutionListener来注册监听器是合适的。但是,如果把它添加到整个测试套件中,会变得很麻烦。

We can address this problem by taking advantage of the support provided by the SpringFactoriesLoader mechanism for the automatic discovery of TestExecutionListener implementations.

我们可以利用SpringFactoriesLoader机制提供的支持来解决这个问题,该机制用于自动发现TestExecutionListener实现。

The spring-test module declares all core default listeners under the org.springframework.test.context.TestExecutionListener key in its META-INF/spring.factories properties file. Similarly, we can register our custom listener by using the above key in our own META-INF/spring.factories properties file:

spring-test模块在其META-INF/spring. factories属性文件中的org.springframework.test.context.TestExecutionListener键下声明了所有核心默认监听器。同样地,我们可以在我们自己的META-INF/spring.plants属性文件中使用上述键来注册我们的自定义监听器

org.springframework.test.context.TestExecutionListener=\
com.baeldung.testexecutionlisteners.CustomTestExecutionListener

4.3. Ordering Default TestExecutionListener Implementations

4.3.对默认的TestExecutionListener实现进行排序

When Spring discovers default TestExecutionListener implementations through the SpringFactoriesLoader mechanism, it’ll sort them by using Spring’s AnnotationAwareOrderComparator. This honors Spring’s Ordered interface and @Order annotation for ordering.

当Spring通过SpringFactoriesLoader机制发现默认的TestExecutionListener实现时,它将通过使用Spring的AnnotationAwareOrderComparator.来对它们进行排序。

Note that all default TestExecutionListener implementations provided by Spring implement Ordered with appropriate values. Therefore, we have to make sure that our custom TestExecutionListener implementation is registered with the proper order. Consequently, we’ve implemented Ordered in our custom listener:

请注意,Spring提供的所有默认TestExecutionListener实现都以适当的值实现Ordered。因此,我们必须确保我们的自定义TestExecutionListener实现以适当的顺序注册。因此,我们已经在我们的自定义监听器中实现了Ordered

public class CustomTestExecutionListener implements TestExecutionListener, Ordered {
    // ...
    @Override
    public int getOrder() {
        return Integer.MAX_VALUE;
    };
}

But, we can use the @Order annotation instead.

但是,我们可以使用@Order注释来代替.

5. Conclusion

5.结论

In this article, we saw how to implement a custom TestExecutionListener. We also looked at the default listeners provided by the Spring framework.

在这篇文章中,我们看到如何实现一个自定义的TestExecutionListener。我们还看了Spring框架所提供的默认监听器。

And, of course, the code accompanying this article is available over on GitHub.

当然,本文所附的代码可在GitHub上获得