TestExecutionListener
配置
Spring 預設按以下確切順序註冊以下 TestExecutionListener
實現:
-
ServletTestExecutionListener
: 為WebApplicationContext
配置 Servlet API mock 物件。 -
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
配置的 mock 物件。
註冊 TestExecutionListener
實現
可以使用 @TestExecutionListeners
註解為測試類、其子類和其巢狀類明確註冊 TestExecutionListener
實現。有關詳細資訊和示例,請參閱註解支援和 @TestExecutionListeners
的 Javadoc。
切換回預設的
TestExecutionListener 實現如果擴充套件了帶有
|
預設 TestExecutionListener
實現的自動發現
使用 @TestExecutionListeners
註冊 TestExecutionListener
實現適用於在有限測試場景中使用的自定義監聽器。但是,如果自定義監聽器需要在整個測試套件中使用,則可能會變得很麻煩。透過 SpringFactoriesLoader
機制支援自動發現預設 TestExecutionListener
實現,解決了這個問題。
例如,spring-test
模組在其 META-INF/spring.factories
屬性檔案中,在 org.springframework.test.context.TestExecutionListener
鍵下聲明瞭所有核心預設 TestExecutionListener
實現。第三方框架和開發人員可以透過自己的 spring.factories
檔案以同樣的方式,將自己的 TestExecutionListener
實現新增到預設監聽器列表中。
TestExecutionListener
實現的排序
當 TestContext Framework 透過上述 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...
}