Spring 中的 @MockitoSpyBean 是什麼?
1. 引言
在測試 Spring Boot 應用程式時,通常會將應用程式上下文中的一些 bean 替換為 mock 或 spy 物件。這樣,我們就可以攔截方法呼叫、驗證互動或覆寫特定元件的行為——所有這些都無需執行底層邏輯。
從 Spring Framework 6.2 開始,引入了一個新的註解@MockitoSpyBean 。此舉旨在將 Mockito 與 Spring TestContext 框架更緊密地集成,從而為開發者在使用 spy 時提供更精細的控制和更可預測的行為。
本文將探討@MockitoSpyBean是什麼,它與傳統的@SpyBean有何不同,以及如何在現代 Spring 測試中使用它。我們還將提供一些實際的程式碼範例,並討論現有測試套件的遷移注意事項。
2. @MockitoSpyBean是什麼?
@MockitoSpyBean註解用於 Spring 測試中,將應用程式上下文中的現有 bean 包裝在 Mockito spy 中。
與模擬物件不同,間諜物件不會完全取代原始 bean。相反,它們允許部分模擬——除非顯式地設置樁,否則會調用真實的方法。這使得它們非常適合那些我們想要驗證方法呼叫或調整行為,但又不想丟棄 bean 真實實作的情況。
在底層,Spring 會在測試生命週期的早期創建真正的 bean,然後用 Mockito spy 包裝。這意味著bean 的依賴項、生命週期回呼和初始化邏輯仍然照常運作。
這也是 Spring Framework 6.2 更廣泛變革的一部分,該框架引入了@ MockitoBean 、 @MockitoSpyBean及相關基礎設施,用統一且更靈活的設計取代了舊的@MockBean和@SpyBean 。
3. @SpyBean對陣@MockitoSpyBean
在@MockitoSpyBean出現之前,我們通常會使用@SpyBean來實現類似的功能。乍一看,這兩個註解似乎可以互換——它們都允許我們為 Spring bean 創建間諜,並使用 Mockito 的驗證 API。然而,它們底層的行為卻有所不同,這種差異在複雜或代理密集型的應用程式中尤其顯著。
舊版的**@SpyBean使用 Mockito 建立一個新的 spy 實例,然後用該實例取代 Spring 上下文中的原始 bean** 。這種方法對大多數測試都有效,但這種替換有時會擾亂 bean 的代理鍊或生命週期,尤其是在使用 AOP 或事務性 bean 時。
另一方面, @MockitoSpyBean工作方式不同。它不會創建一個替代對象,而是獲取 Spring 已經創建的真實 bean,並用一個 spy 對象將其包裝起來。因此,bean 的內部配置和代理程式保持不變,其在測試中的行為更接近生產環境中的行為。
這一細微的改動使得**@MockitoSpyBean註解在現代 Spring 應用中具有代理安全性,且行為更可預測**。另外值得注意的是,舊版註解已被視為遺留功能,預計將在未來的 Spring 主要版本中移除。
4. @MockitoSpyBean的實際應用
現在我們已經了解了@MockitoSpyBean工作原理,接下來讓我們寫一些程式碼來實際體驗一下。我們使用之前提供的程式碼範例來了解如何遷移舊版註解:
@Autowired
OrderRepository orderRepository;
@MockitoSpyBean
NotificationService notificationService;
@MockitoSpyBean
OrderService orderService;
@Test
void givenNotificationServiceIsUsingSpyBean_whenOrderServiceIsCalled_thenNotificationServiceSpyBeanShouldBeInvoked() {
Order orderInput = new Order(null, "Test", 1.0, "17 St Andrews Croft, Leeds ,LS17 7TP");
doReturn(true).when(notificationService)
.raiseAlert(any(Order.class));
Order order = orderService.save(orderInput);
Assertions.assertNotNull(order);
Assertions.assertNotNull(order.getId());
verify(notificationService).notify(any(Order.class));
}
如上面的程式碼所示,從舊版註解遷移非常簡單。我們只需將舊的@SpyBean註解替換為@MockitoSpyBean ,測試無需任何其他更改即可繼續正常運行。
這凸顯了新註解的關鍵優勢之一。它可直接取代現有測試,同時在 Mockito 和 Spring TestContext 之間提供更可靠的框架級整合。
5. 結論
在本文中,我們探討了 Spring Framework 6.2 中引入的新@MockitoSpyBean註解。
它提供了一種現代化的框架級替代方案,取代了舊版的@SpyBean ,提供了更強大的功能、與 Spring 代理系統更好的集成,以及在不同測試環境中更一致的行為。 @MockitoSpyBean透過封裝(而非替換)真實的 bean,保留了 bean 的生命週期、依賴項和代理程式。這使得它尤其適用於整合測試,因為我們既需要驗證真實的應用程式邏輯,又需要保留觀察或模擬特定互動的能力。
隨著 Spring 生態系統的不斷發展, @MockitoSpyBean是新專案的建議選擇,並且很可能成為未來 Spring 版本中基於 spy 的測試的標準。
與往常一樣,文章中的程式碼可透過 GitHub 儲存庫取得。