Spring 提供了以下 TestExecutionListener 的实现,这些实现在默认情况下被注册,完全按照以下顺序:

  • ServletTestExecutionListener:为 WebApplicationContext 配置 Servlet API mocks。
  • DirtiesContextBeforeModesTestExecutionListener:处理 before 模式的 @DirtiesContext 注解。
  • ApplicationEventsTestExecutionListener:提供对 ApplicationEvents 的支持。
  • DependencyInjectionTestExecutionListener:为测试实例提供依赖性注入。
  • DirtiesContextTestExecutionListener:处理 after 模式的 @DirtiesContext 注解。
  • TransactionalTestExecutionListener:提供具有默认回滚语义的事务性测试执行。
  • SqlScriptsTestExecutionListener:运行通过使用 @Sql 注解配置的 SQL 脚本。
  • EventPublishingTestExecutionListener:将测试执行事件发布到测试的 ApplicationContext(见测试执行事件)。

注册 TestExecutionListener 实现

你可以通过使用 @TestExecutionListeners 注解为一个测试类及其子类注册 TestExecutionListener 实现。详情和例子见 注解支持@TestExecutionListeners 的 javadoc

自动发现默认的 TestExecutionListener 实现

通过使用 @TestExecutionListeners 注册 TestExecutionListener 实现,适合于在有限的测试场景中使用的自定义监听器。然而,如果一个自定义监听器需要在整个测试套件中使用,它可能变得很麻烦。这个问题通过支持通过 SpringFactoriesLoader 机制自动发现默认 TestExecutionListener 实现来解决。

具体来说,spring-test 模块在其 META-INF/spring.plants 属性文件的 org.springframework.test.context.TestExecutionListener 键下声明了所有核心默认 TestExecutionListener 实现。第三方框架和开发者可以通过他们自己的 META-INF/spring.plants 属性文件,以同样的方式向默认监听器列表贡献他们自己的 TestExecutionListener 实现。

对 TestExecutionListener 实现进行排序

当 TestContext 框架通过上述 SpringFactoriesLoader 机制发现默认的 TestExecutionListener 实现时,通过使用 Spring 的AnnotationAwareOrderComparator 对实例化的监听器进行排序,它尊重 Spring 的 Ordered 接口和 @Order 注解的排序。AbstractTestExecutionListener 和 Spring 提供的所有默认 TestExecutionListener 实现都使用适当的值实现了 Ordered。因此,第三方框架和开发人员应该确保他们的默认 TestExecutionListener 实现通过实现 Ordered 或声明 @Order 而以适当的顺序注册。参见核心默认 TestExecutionListener 实现的 getOrder()方法的 javadoc,以了解分配给每个核心监听器的值的细节。

合并 TestExecutionListener 的实现

如果一个自定义的 TestExecutionListener 通过 @TestExecutionListeners 注册,默认的监听器就不会被注册。在大多数常见的测试场景中,这有效地迫使开发者在任何自定义监听器之外手动声明所有默认监听器。下面的列表演示了这种配置风格:

  1. @ContextConfiguration
  2. @TestExecutionListeners({
  3. MyCustomTestExecutionListener.class,
  4. ServletTestExecutionListener.class,
  5. DirtiesContextBeforeModesTestExecutionListener.class,
  6. DependencyInjectionTestExecutionListener.class,
  7. DirtiesContextTestExecutionListener.class,
  8. TransactionalTestExecutionListener.class,
  9. SqlScriptsTestExecutionListener.class
  10. })
  11. class MyTest {
  12. // class body...
  13. }

这种方法的挑战在于,它要求开发者确切地知道哪些监听器是默认注册的。此外,默认监听器的集合会随着版本的变化而变化—例如, SqlScriptsTestExecutionListener 是在 Spring Framework 4.1 中引入的,而 DirtiesContextBeforeModesTestExecutionListener 是在 Spring Framework 4.2 中引入的。此外,Spring Boot 和 Spring Security 等第三方框架通过使用上述的自动发现机制,注册了自己的默认 TestExecutionListener 实现。

为了避免必须意识到并重新声明所有的默认监听器,你可以将 @TestExecutionListeners 的 mergeMode 属性设置为MergeMode.MERGE_WITH_DEFAULTS。MERGE_WITH_DEFAULTS 表示本地声明的监听器应该与默认监听器合并。合并算法确保从列表中删除重复的内容,并且根据 AnnotationAwareOrderComparator 的语义对合并后的监听器集合进行排序,详见 排序的 TestExecutionListener 实现。如果一个监听器实现了 Ordered 或者被 @Order 注解了,它可以影响它与默认值合并的位置。否则,本地声明的监听器在合并时被追加到默认监听器的列表中。

例如,如果前面例子中的 MyCustomTestExecutionListener 类将其顺序值(例如 500)配置为小于 ServletTestExecutionListener 的顺序(刚好是 1000),那么 MyCustomTestExecutionListener 就可以自动与 ServletTestExecutionListener 前面的默认列表合并,前面的例子可以替换为以下内容:

  1. @ContextConfiguration
  2. @TestExecutionListeners(
  3. listeners = MyCustomTestExecutionListener.class,
  4. mergeMode = MERGE_WITH_DEFAULTS
  5. )
  6. class MyTest {
  7. // class body...
  8. }