@MockitoBean@MockitoSpyBean

@MockitoBean@MockitoSpyBean 可用於測試類中,分別用 Mockito 的 mockspy 替換測試的 ApplicationContext 中的 bean。在後一種情況下,原始 bean 的早期例項會被捕獲並由 spy 包裝。

註解可以透過以下方式應用。

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

  • @Nested 測試類的外層類的非靜態欄位上,或在 @Nested 測試類上方的型別層次結構或外層類層次結構中的任何類上。

  • 在測試類或其任何超類或測試類上方的型別層次結構中實現的介面的型別級別上。

  • @Nested 測試類的外層類的型別級別上,或在 @Nested 測試類上方的型別層次結構或外層類層次結構中的任何類或介面上。

@MockitoBean@MockitoSpyBean 在欄位上宣告時,要 mock 或 spy 的 bean 會從註解欄位的型別中推斷出來。如果 ApplicationContext 中存在多個候選物件,可以在欄位上宣告 @Qualifier 註解以幫助消除歧義。在沒有 @Qualifier 註解的情況下,註解欄位的名稱將用作 fallback 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 註解使用 REPLACE_OR_CREATE bean 覆蓋策略。如果不存在相應的 bean,將建立一個新 bean。但是,您可以透過將 enforceOverride 屬性設定為 true 來切換到 REPLACE 策略,例如 @MockitoBean(enforceOverride = true)

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

如 Mockito 文件中所述,有時使用 Mockito.when() 來 stub spy 是不合適的,例如,如果在 spy 上呼叫真實方法會導致不希望的副作用。

為避免此類不希望的副作用,請考慮使用 Mockito.doReturn(…​).when(spy)…​Mockito.doThrow(…​).when(spy)…​Mockito.doNothing().when(spy)…​ 和類似方法。

當使用 @MockitoBean 來 mock 非單例 bean 時,非單例 bean 將被替換為單例 mock,並且相應的 bean 定義將轉換為 singleton。因此,如果您 mock prototype 或 scoped bean,mock 將被視為 singleton

類似地,當使用 @MockitoSpyBean 為非單例 bean 建立 spy 時,相應的 bean 定義將轉換為 singleton。因此,如果您為 prototype 或 scoped bean 建立 spy,spy 將被視為 singleton

當使用 @MockitoBean 來 mock 由 FactoryBean 建立的 bean 時,FactoryBean 將被替換為 FactoryBean 建立的物件型別的單例 mock。

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

此外,@MockitoSpyBean 不能用於 spy scoped proxy,例如,用 @Scope(proxyMode = ScopedProxyMode.TARGET_CLASS) 註解的 bean。任何這樣做的嘗試都將以異常失敗。

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

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

@MockitoBean 示例

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

  • Java

@SpringJUnitConfig(TestConfig.class)
class BeanOverrideTests {

	@MockitoBean (1)
	CustomService customService;

	// tests...
}
1 將型別為 CustomService 的 bean 替換為 Mockito mock。

在上面的示例中,我們正在為 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 將名為 service 的 bean 替換為 Mockito mock。

以下 @SharedMocks 註解按型別註冊了兩個 mock,按名稱註冊了一個 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 以進行 stubverify
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,按名稱註冊了一個 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 以進行 stubverify
spy 也可以注入到 @Configuration 類或 ApplicationContext 中其他與測試相關的元件中,以便使用 Mockito 的 stubbing API 配置它們。
© . This site is unofficial and not affiliated with VMware.