Spring Framework 6.2.0-M1:測試中覆寫 Bean

工程 | Simon Baslé | 2024 年 4 月 16 日 | ...

Spring Framework 6.2.0-M1 已發佈,其中包含解決超過一百個問題的變更。其中包含 Spring 測試支援中的一系列新功能。

在這篇文章中,我想帶您了解其中一個新的測試功能:Bean 覆寫支援。

先前的情況

使用 Spring TestContext Framework,您可以透過註解驅動模型,輕鬆驗證 Spring 應用程式在整合測試中的正確配置。

在單元測試中,依賴注入和 Spring 設計原則使您的程式碼更少依賴容器,並更容易手動 Stub 或 Mock 元件的依賴項,以便隔離測試它。在整合測試中,這不太相關,因為測試旨在涵蓋元件的正確配置。儘管您可能會發現需要替換整合測試中 Bean 的情況。

Spring Framework 團隊通常不建議重新定義 Bean。雖然目前在 BeanDefinitionRegistry 的預設實作中可以透過標誌來實現,但我們計劃棄用它,而 Spring Boot 已經預設關閉 Bean 覆寫來選擇退出。

然而,這在生產程式碼中更令人擔憂,我們認識到在測試中覆寫 Bean 是有用且合理的。因此,我們的目標是在該領域為常見的覆寫情境提供一流的安排。

在 Spring Framework 6.2.0-M1 中,我們引入了一個可擴展的 Bean 覆寫功能,它將允許您精確且明確地替換整合測試中的一個或多個 Bean 定義,同時防止在生產程式碼或測試的其他部分中發生此類意外變更。

使用 @TestBean 的簡單方法基礎覆寫

Spring TestContext Framework 現在提供了一個簡單的 Bean 覆寫支援實作:@TestBean 註解。

覆寫名為 example 的 Bean 分為三個步驟:新增一個以 Bean 名稱命名的欄位,使用 @TestBean 註解標註它,並新增一個名為 exampleTestOverride 的 0 參數 static 工廠方法。在該工廠方法中,例如,如果 Bean 類型是介面,您可以傳回簡化的實作,如下列範例所示

@Configuration
class ProdConfiguration {

  @Bean
  MyService customService() {
    return new ProdServiceImpl();
  }
}

@SpringJUnitConfig
class MyServiceIntegrationTests {

  @TestBean
  MyService customService;

  static MyService customServiceTestOverride() {
    return new SimplifiedServiceImpl();
  }

  @Test
  void test(ApplicationContext context) {
    assertThat(context.getBean("customService")
      .isSameAs(this.customService)
      .isInstanceOf(SimplifiedServiceImpl.class);
    //...
  }
}

除非為 @TestBean 註解提供 beanName 屬性,否則註解欄位的名稱會被解釋為目標 Bean 的名稱。

methodName 參數也可以用於指向不遵循 {beanName}TestOverride 預設命名慣例的工廠方法。

Bean 覆寫機制負責解析此註解,並負責替換登錄檔中現有的 Bean 定義。測試類別中的 customService 欄位也會注入由 customServiceTestOverride 工廠方法產生的覆寫實例。

基於 Mockito 的覆寫與 @MockitoBean@MockitoSpyBean

第二個 Bean 覆寫實作基於 Mockito 函式庫。它帶有兩個註解:@MockitoBean 用於自動將目標單例 Bean 替換為 Mock 物件,而 @MockitoSpyBean 用於將 Bean 包裝在 Spy 物件中。

每個註解都有特定於 Mockito 的屬性,以便進一步配置應如何 Mock 目標 Bean。這包括支援指定如何在測試之間重設 Mock 物件,如下列範例所示

@Configuration
class ProdConfiguration {

  @Bean
  MyService customService() {
    return new ProdService();
  }
}

@SpringJUnitConfig
class MyServiceIntegrationTests {

  @MockitoSpyBean(reset = MockReset.NONE)
  MyService customService;

  @Test
  void test() {
    //...
  }
}

在上面的範例中,Spy 物件在測試之間不會被重設。預設情況下,Mock 物件和 Spy 物件在測試方法執行重設。

請注意,為了 Spy 一個 Bean,首先必須存在 Spy 類別的實際實例。除了更常見的替換 Bean 定義的情況之外,Bean 覆寫功能還支援這種特殊情況,並允許在 Bean 實例化後從中繼資料建立覆寫。

使用您自己的實作擴展

測試支援中的新 Bean 覆寫以註解基礎模型的形式出現,適用於您測試類別中的欄位。它是可擴展和可自訂的,上面介紹的 3 個註解只是我們開箱即用提供的預設實作。

實作您自己的 Bean 覆寫風格與實作以下內容一樣簡單

  • 一個使用 @BeanOverride Meta-Annotation 註解的註解,它定義要使用的 BeanOverrideProcessor
  • BeanOverrideProcessor 實作本身。
  • 處理器提供的一個或多個具體 OverrideMetadata 實作。

Spring TestContext Framework 解析測試類別,尋找任何使用 @BeanOverride Meta-Annotation 註解的欄位,並實例化相關的 BeanOverrideProcessor,以便註冊 OverrideMetadata 的實例。

然後,BeanFactoryPostProcessor 將使用該資訊來更改上下文,註冊和替換每個中繼資料定義的 Bean 定義。

結論

Spring TestContext Framework 現在提供兩種在測試中覆寫 Bean 的方法,而沒有意外副作用的風險。Bean 覆寫機制是可擴展的,例如,如果您喜歡使用 Mockito 以外的 Mock 函式庫,這可能會派上用場。

我們期待社群對此功能的意見回饋,包括對此第一個迭代版本的改進建議。

同時,祝您編碼愉快!

取得 Spring 電子報

與 Spring 電子報保持聯繫

訂閱

搶先一步

VMware 提供培訓和認證,以加速您的進展。

了解更多

取得支援

Tanzu Spring 在一個簡單的訂閱中為 OpenJDK™、Spring 和 Apache Tomcat® 提供支援和二進位檔案。

了解更多

即將到來的活動

查看 Spring 社群中所有即將到來的活動。

查看所有