TestExecutionListener 配置
Spring 提供了以下默认注册的 TestExecutionListener 实现,其顺序如下:
-
ServletTestExecutionListener:为WebApplicationContext配置 Servlet API 模拟。 -
DirtiesContextBeforeModesTestExecutionListener:处理 "before" 模式的@DirtiesContext注解。 -
ApplicationEventsTestExecutionListener:提供对ApplicationEvents的支持。 -
BeanOverrideTestExecutionListener:提供对 测试中的 Bean 覆盖 的支持。 -
DependencyInjectionTestExecutionListener:为测试实例提供依赖注入。 -
MicrometerObservationRegistryTestExecutionListener:提供对 Micrometer 的ObservationRegistry的支持。 -
DirtiesContextTestExecutionListener:处理 "after" 模式的@DirtiesContext注解。 -
CommonCachesTestExecutionListener:如果需要,清除测试的ApplicationContext中的资源缓存。 -
TransactionalTestExecutionListener:提供带有默认回滚语义的事务性测试执行。 -
SqlScriptsTestExecutionListener:运行通过@Sql注解配置的 SQL 脚本。 -
EventPublishingTestExecutionListener:向测试的ApplicationContext发布测试执行事件(参见 测试执行事件)。 -
MockitoResetTestExecutionListener:根据@MockitoBean或@MockitoSpyBean的配置重置模拟。
注册 TestExecutionListener 实现
您可以使用 @TestExecutionListeners 注解为测试类、其子类及其嵌套类显式注册 TestExecutionListener 实现。有关详细信息和示例,请参阅 注解支持 和 @TestExecutionListeners 的 javadoc。
|
切换到默认
TestExecutionListener 实现如果您扩展了一个带有
|
自动发现默认 TestExecutionListener 实现
使用 @TestExecutionListeners 注册 TestExecutionListener 实现适用于在有限测试场景中使用的自定义监听器。但是,如果自定义监听器需要在整个测试套件中使用,这可能会变得很麻烦。这个问题通过 SpringFactoriesLoader 机制对自动发现默认 TestExecutionListener 实现的支持得到了解决。
例如,spring-test 模块在其 META-INF/spring.factories 属性文件 中声明了所有核心默认 TestExecutionListener 实现,键为 org.springframework.test.context.TestExecutionListener。第三方框架和开发人员可以通过他们自己的 spring.factories 文件以同样的方式向默认监听器列表贡献他们自己的 TestExecutionListener 实现。
对 TestExecutionListener 实现进行排序
当 TestContext 框架通过 上述 SpringFactoriesLoader 机制发现默认的 TestExecutionListener 实现时,实例化的监听器会使用 Spring 的 AnnotationAwareOrderComparator 进行排序,该比较器尊重 Spring 的 Ordered 接口和 @Order 注解进行排序。AbstractTestExecutionListener 和 Spring 提供的所有默认 TestExecutionListener 实现都实现了带有适当值的 Ordered 接口。因此,第三方框架和开发人员应确保通过实现 Ordered 或声明 @Order 来按正确的顺序注册其默认 TestExecutionListener 实现。有关为每个核心监听器分配的值的详细信息,请参阅核心默认 TestExecutionListener 实现的 getOrder() 方法的 javadoc。
合并 TestExecutionListener 实现
如果通过 @TestExecutionListeners 注册了自定义 TestExecutionListener,则不会注册默认监听器。在大多数常见的测试场景中,这实际上会强制开发人员手动声明所有默认监听器以及任何自定义监听器。以下列表演示了这种配置方式
-
Java
-
Kotlin
@ContextConfiguration
@TestExecutionListeners({
MyCustomTestExecutionListener.class,
ServletTestExecutionListener.class,
DirtiesContextBeforeModesTestExecutionListener.class,
DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class,
SqlScriptsTestExecutionListener.class
})
class MyTest {
// class body...
}
@ContextConfiguration
@TestExecutionListeners(
MyCustomTestExecutionListener::class,
ServletTestExecutionListener::class,
DirtiesContextBeforeModesTestExecutionListener::class,
DependencyInjectionTestExecutionListener::class,
DirtiesContextTestExecutionListener::class,
TransactionalTestExecutionListener::class,
SqlScriptsTestExecutionListener::class
)
class MyTest {
// class body...
}
这种方法的挑战在于,它要求开发人员准确知道哪些监听器是默认注册的。此外,默认监听器集可能因版本而异,例如,SqlScriptsTestExecutionListener 在 Spring Framework 4.1 中引入,DirtiesContextBeforeModesTestExecutionListener 在 Spring Framework 4.2 中引入。此外,像 Spring Boot 和 Spring Security 这样的第三方框架使用 上述自动发现机制 注册它们自己的默认 TestExecutionListener 实现。
为了避免必须了解和重新声明所有默认监听器,您可以将 @TestExecutionListeners 的 mergeMode 属性设置为 MergeMode.MERGE_WITH_DEFAULTS。MERGE_WITH_DEFAULTS 表示本地声明的监听器应与默认监听器合并。合并算法确保从列表中删除重复项,并且根据 对 TestExecutionListener 实现进行排序 中描述的 AnnotationAwareOrderComparator 的语义对合并后的监听器集进行排序。如果监听器实现了 Ordered 或使用 @Order 进行注解,它会影响其与默认监听器合并的位置。否则,本地声明的监听器在合并时会附加到默认监听器列表的末尾。
例如,如果前一个示例中的 MyCustomTestExecutionListener 类将其 order 值配置为(例如,500)小于 ServletTestExecutionListener 的顺序(恰好是 1000),那么 MyCustomTestExecutionListener 就可以自动与默认列表合并,排在 ServletTestExecutionListener 之前,前一个示例可以替换为以下内容
-
Java
-
Kotlin
@ContextConfiguration
@TestExecutionListeners(
listeners = MyCustomTestExecutionListener.class,
mergeMode = MERGE_WITH_DEFAULTS
)
class MyTest {
// class body...
}
@ContextConfiguration
@TestExecutionListeners(
listeners = [MyCustomTestExecutionListener::class],
mergeMode = MERGE_WITH_DEFAULTS
)
class MyTest {
// class body...
}