測試中的 Bean 覆蓋

測試中的 Bean 覆蓋(Bean overriding)是指透過在測試類或測試類中的一個或多個非靜態欄位上使用註解,來覆蓋測試類的 ApplicationContext 中的特定 Bean 的能力。

此功能旨在作為一種風險較低的替代方案,以取代透過 @Bean 註冊 Bean 並將 DefaultListableBeanFactorysetAllowBeanDefinitionOverriding 標誌設定為 true 的做法。

Spring TestContext 框架提供了兩組用於 Bean 覆蓋的註解。

前者純粹依賴於 Spring,而後者則依賴於 Mockito 第三方庫。

自定義 Bean 覆蓋支援

上面提到的三個註解基於 @BeanOverride 元註解和相關的基礎設施構建,這使得可以定義自定義的 Bean 覆蓋變體。

要實現自定義 Bean 覆蓋支援,需要以下內容:

  • 使用 @BeanOverride 元註解標記的註解,該註解定義了要使用的 BeanOverrideProcessor

  • 一個自定義的 BeanOverrideProcessor 實現

  • 由處理器建立一個或多個具體的 BeanOverrideHandler 實現

Spring TestContext 框架包含對以下 API 的實現,這些 API 支援 Bean 覆蓋並負責設定其餘基礎設施。

  • 一個 BeanFactoryPostProcessor

  • 一個 ContextCustomizerFactory

  • 一個 TestExecutionListener

spring-test 模組在其 META-INF/spring.factories 屬性檔案中註冊了後兩者的實現(BeanOverrideContextCustomizerFactoryBeanOverrideTestExecutionListener)。

Bean 覆蓋基礎設施會搜尋測試類上的註解以及測試類中非靜態欄位上帶有 @BeanOverride 元註解的註解,並例項化相應的 BeanOverrideProcessor,該處理器負責建立適當的 BeanOverrideHandler

內部的 BeanOverrideBeanFactoryPostProcessor 然後使用 bean 覆蓋處理器,根據相應的 BeanOverrideStrategy 定義,透過建立、替換或包裝 bean 來修改測試的 ApplicationContext

REPLACE (替換)

替換 Bean。如果相應的 Bean 不存在,則丟擲異常。

REPLACE_OR_CREATE (替換或建立)

如果 Bean 存在則替換。如果相應的 Bean 不存在,則建立新的 Bean。

WRAP (包裝)

檢索原始 Bean 並對其進行包裝。

只有 singleton Bean 可以被覆蓋。任何嘗試覆蓋非 singleton Bean 的行為都將導致異常。

替換由 FactoryBean 建立的 Bean 時,FactoryBean 本身將被替換為由適用的 BeanOverrideHandler 建立的 Bean 覆蓋例項所對應的 singleton Bean。

包裝由 FactoryBean 建立的 Bean 時,將包裝由 FactoryBean 建立的物件,而不是 FactoryBean 本身。

與 Spring 的自動裝配機制(例如,解析 @Autowired 欄位)相比,TestContext 框架中的 Bean 覆蓋基礎設施在定位 Bean 時可執行的啟發式操作有限。要麼 BeanOverrideProcessor 可以計算要覆蓋的 Bean 的名稱,要麼可以根據被註解欄位的型別及其限定符註解來明確選擇 Bean。

通常,BeanOverrideFactoryPostProcessor 會“按型別”選擇 Bean。或者,使用者也可以在自定義註解中直接提供 Bean 名稱。

BeanOverrideProcessor 實現也可以基於約定或其他方法在內部計算 Bean 名稱。