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...
}