@MockitoBean@MockitoSpyBean

@MockitoBean@MockitoSpyBean 註解可用於測試類中,以將測試的 ApplicationContext 中的 Bean 分別覆蓋為 Mockito 的 mockspy。在後一種情況下,會捕獲原始 Bean 的早期例項並由 spy 進行包裝。

這些註解可以透過以下方式應用:

  • 在測試類或其任何超類中的非靜態欄位上。

  • @Nested 測試類的封閉類中的非靜態欄位上,或在 @Nested 測試類之上的型別層級或封閉類層級中的任何類中。

  • 在測試類或測試類之上的型別層級中的任何超類或實現的介面的型別級別上。

  • @Nested 測試類的封閉類的型別級別上,或在 @Nested 測試類之上的型別層級或封閉類層級中的任何類或介面上。

當在欄位上宣告 @MockitoBean@MockitoSpyBean 時,要 mock 或 spy 的 Bean 會從被註解欄位的型別推斷出來。如果在 ApplicationContext 中存在多個候選,可以在欄位上宣告 @Qualifier 註解以幫助消除歧義。如果沒有 @Qualifier 註解,被註解欄位的名稱將用作 回退限定符。或者,你可以透過在註解中設定 valuename 屬性來顯式指定要 mock 或 spy 的 Bean 名稱。

當在型別級別宣告 @MockitoBean@MockitoSpyBean 時,要 mock 或 spy 的 Bean 型別(或多個 Bean 型別)必須透過註解中的 types 屬性提供 – 例如,@MockitoBean(types = {OrderService.class, UserService.class})。如果在 ApplicationContext 中存在多個候選,你可以透過設定 name 屬性來顯式指定要 mock 或 spy 的 Bean 名稱。但是請注意,如果配置了顯式的 Bean name,則 types 屬性必須只包含一個型別 – 例如,@MockitoBean(name = "ps1", types = PrintingService.class)

為了支援 mock 配置的重用,@MockitoBean@MockitoSpyBean 可用作元註解來建立自定義的 組合註解 – 例如,在一個註解中定義通用的 mock 或 spy 配置,該註解可以在整個測試套件中重複使用。@MockitoBean@MockitoSpyBean 也可以在型別級別用作可重複註解 — 例如,按名稱 mock 或 spy 多個 Bean。

限定符,包括欄位的名稱,用於確定是否需要建立單獨的 ApplicationContext。如果您使用此功能在多個測試類中 mock 或 spy 同一個 Bean,請確保欄位命名一致,以避免建立不必要的上下文。

@MockitoBean@MockitoSpyBean@ContextHierarchy 結合使用可能會導致意外結果,因為每個 @MockitoBean@MockitoSpyBean 預設會應用於所有上下文層級級別。為了確保特定的 @MockitoBean@MockitoSpyBean 僅應用於單個上下文層級級別,請將 contextName 屬性設定為匹配配置的 @ContextConfiguration 名稱 – 例如,@MockitoBean(contextName = "app-config")@MockitoSpyBean(contextName = "app-config")

更多詳細資訊和示例請參閱帶有 Bean 覆蓋的上下文層級結構

每個註解還定義了 Mockito 特有的屬性來微調 mocking 行為。

@MockitoBean 註解使用用於Bean 覆蓋的 REPLACE_OR_CREATE 策略。如果對應的 Bean 不存在,將建立一個新的 Bean。但是,你可以透過將 enforceOverride 屬性設定為 true 來切換到 REPLACE 策略 – 例如,@MockitoBean(enforceOverride = true)

@MockitoSpyBean 註解使用WRAP 策略,並且原始例項會被包裝到 Mockito spy 中。此策略要求恰好存在一個候選 Bean。

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

當使用 @MockitoBean mock 由 FactoryBean 建立的 Bean 時,FactoryBean 將被替換為由 FactoryBean 建立的物件型別的 singleton mock。

當使用 @MockitoSpyBeanFactoryBean 建立 spy 時,將為由 FactoryBean 建立的物件建立 spy,而不是為 FactoryBean 本身。

@MockitoBean@MockitoSpyBean 欄位的可見性沒有限制。

因此,這些欄位可以是 publicprotected、包私有(預設可見性)或 private,具體取決於專案的需求或編碼實踐。

@MockitoBean 示例

以下示例展示瞭如何使用 @MockitoBean 註解的預設行為。

  • Java

@SpringJUnitConfig(TestConfig.class)
class BeanOverrideTests {

	@MockitoBean (1)
	CustomService customService;

	// tests...
}
1 使用 Mockito mock 替換型別為 CustomService 的 Bean。

在上面的示例中,我們正在為 CustomService 建立 mock。如果存在該型別的多個 Bean,則考慮名稱為 customService 的 Bean。否則,測試將失敗,您需要提供某種限定符來標識要覆蓋哪個 CustomService Bean。如果不存在這樣的 Bean,將建立一個具有自動生成 Bean 名稱的 Bean。

以下示例使用按名稱查詢,而不是按型別查詢。如果不存在名稱為 service 的 Bean,則建立一個新的。

  • Java

@SpringJUnitConfig(TestConfig.class)
class BeanOverrideTests {

	@MockitoBean("service") (1)
	CustomService customService;

	// tests...

}
1 使用 Mockito mock 替換名稱為 service 的 Bean。

以下 @SharedMocks 註解註冊了兩個按型別和一按名稱的 mock。

  • Java

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@MockitoBean(types = {OrderService.class, UserService.class}) (1)
@MockitoBean(name = "ps1", types = PrintingService.class) (2)
public @interface SharedMocks {
}
1 註冊 OrderServiceUserService 型別的 mock。
2 註冊名稱為 PrintingService 的 mock。

以下示例演示瞭如何在測試類中使用 @SharedMocks

  • Java

@SpringJUnitConfig(TestConfig.class)
@SharedMocks (1)
class BeanOverrideTests {

	@Autowired OrderService orderService; (2)

	@Autowired UserService userService; (2)

	@Autowired PrintingService ps1; (2)

	// Inject other components that rely on the mocks.

	@Test
	void testThatDependsOnMocks() {
		// ...
	}
}
1 透過自定義 @SharedMocks 註解註冊通用 mock。
2 可選地注入 mock 以進行 存根驗證
這些 mock 也可以注入到 @Configuration 類或 ApplicationContext 中其他與測試相關的元件中,以便使用 Mockito 的 stubbing API 配置它們。

@MockitoSpyBean 示例

以下示例展示瞭如何使用 @MockitoSpyBean 註解的預設行為。

  • Java

@SpringJUnitConfig(TestConfig.class)
class BeanOverrideTests {

	@MockitoSpyBean (1)
	CustomService customService;

	// tests...
}
1 使用 Mockito spy 包裝型別為 CustomService 的 Bean。

在上面的示例中,我們正在包裝型別為 CustomService 的 Bean。如果存在該型別的多個 Bean,則考慮名稱為 customService 的 Bean。否則,測試將失敗,您需要提供某種限定符來標識要 spy 的 CustomService Bean。

以下示例使用按名稱查詢,而不是按型別查詢。

  • Java

@SpringJUnitConfig(TestConfig.class)
class BeanOverrideTests {

	@MockitoSpyBean("service") (1)
	CustomService customService;

	// tests...
}
1 使用 Mockito spy 包裝名稱為 service 的 Bean。

以下 @SharedSpies 註解註冊了兩個按型別和一按名稱的 spy。

  • Java

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@MockitoSpyBean(types = {OrderService.class, UserService.class}) (1)
@MockitoSpyBean(name = "ps1", types = PrintingService.class) (2)
public @interface SharedSpies {
}
1 註冊 OrderServiceUserService 型別的 spy。
2 註冊名稱為 PrintingService 的 spy。

以下示例演示瞭如何在測試類中使用 @SharedSpies

  • Java

@SpringJUnitConfig(TestConfig.class)
@SharedSpies (1)
class BeanOverrideTests {

	@Autowired OrderService orderService; (2)

	@Autowired UserService userService; (2)

	@Autowired PrintingService ps1; (2)

	// Inject other components that rely on the spies.

	@Test
	void testThatDependsOnMocks() {
		// ...
	}
}
1 透過自定義 @SharedSpies 註解註冊通用 spy。
2 可選地注入 spy 以進行 存根驗證
這些 spy 也可以注入到 @Configuration 類或 ApplicationContext 中其他與測試相關的元件中,以便使用 Mockito 的 stubbing API 配置它們。