@MockitoBean
和 @MockitoSpyBean
@MockitoBean
和
@MockitoSpyBean
可用于测试类中,以使用 Mockito 的 mock 或 spy 分别覆盖测试的 ApplicationContext
中的 bean。在后一种情况下,原始 bean 的早期实例被捕获并由 spy 包装。
这些注解可以通过以下方式应用。
-
在测试类或其任何超类中的非静态字段上。
-
在
@Nested
测试类的封闭类中的非静态字段上,或在@Nested
测试类上方的类型层次结构或封闭类层次结构中的任何类中。 -
在测试类或其上方类型层次结构中的任何超类或已实现的接口的类型级别上。
-
在
@Nested
测试类的封闭类上,或在@Nested
测试类上方的类型层次结构或封闭类层次结构中的任何类或接口的类型级别上。
当 @MockitoBean
或 @MockitoSpyBean
在字段上声明时,要模拟或监视的 bean 从带注解字段的类型推断。如果 ApplicationContext
中存在多个候选对象,可以在字段上声明 @Qualifier
注解以帮助消除歧义。在没有 @Qualifier
注解的情况下,带注解字段的名称将用作 回退限定符。或者,您可以通过设置注解中的 value
或 name
属性来显式指定要模拟或监视的 bean 名称。
当 @MockitoBean
或 @MockitoSpyBean
在类型级别声明时,要模拟或监视的 bean 类型(或多个 bean)必须通过注解中的 types
属性提供——例如,@MockitoBean(types = {OrderService.class, UserService.class})
。如果 ApplicationContext
中存在多个候选对象,您可以通过设置 name
属性来显式指定要模拟或监视的 bean 名称。但请注意,如果配置了显式 bean name
,则 types
属性必须包含单个类型——例如,@MockitoBean(name = "ps1", types = PrintingService.class)
。
为了支持 mock 配置的重用,@MockitoBean
和 @MockitoSpyBean
可以用作元注解来创建自定义的 组合注解——例如,在一个注解中定义通用的 mock 或 spy 配置,以便在整个测试套件中重用。@MockitoBean
和 @MockitoSpyBean
也可以作为可重复注解在类型级别使用——例如,按名称模拟或监视多个 bean。
限定符,包括字段的名称,用于确定是否需要创建单独的 ApplicationContext
。如果您使用此功能在多个测试类中模拟或监视同一个 bean,请确保一致地命名这些字段,以避免创建不必要的上下文。
将 @MockitoBean
或 @MockitoSpyBean
与 @ContextHierarchy
结合使用可能会导致不良结果,因为每个 @MockitoBean
或 @MockitoSpyBean
默认将应用于所有上下文层次结构级别。为确保特定的 @MockitoBean
或 @MockitoSpyBean
仅应用于单个上下文层次结构级别,请将 contextName
属性设置为与配置的 @ContextConfiguration
名称匹配——例如,@MockitoBean(contextName = "app-config")
或
@MockitoSpyBean(contextName = "app-config")
。
有关更多详细信息和示例,请参阅
带 bean 覆盖的上下文层次结构。
每个注解还定义了 Mockito 特定的属性来微调模拟行为。
@MockitoBean
注解使用 REPLACE_OR_CREATE
bean 覆盖策略。
如果不存在相应的 bean,则会创建一个新 bean。但是,您可以通过将 enforceOverride
属性设置为 true
来切换到 REPLACE
策略——例如,@MockitoBean(enforceOverride = true)
。
@MockitoSpyBean
注解使用 WRAP
策略,
并且原始实例被包装在 Mockito spy 中。此策略要求恰好存在一个候选 bean。
如 Mockito 文档中所述,有时使用 |
只有 单例 bean 可以被覆盖。任何覆盖非单例 bean 的尝试都将导致异常。
当使用 |
对 |
@MockitoBean
示例
以下示例展示了如何使用 @MockitoBean
注解的默认行为。
- Java
-
@SpringJUnitConfig(TestConfig.class) class BeanOverrideTests { @MockitoBean [id="CO1-1"][id="CO1-1"][id="CO1-1"](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") [id="CO2-1"][id="CO1-2"][id="CO2-1"](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}) [id="CO3-1"][id="CO1-3"][id="CO3-1"](1) @MockitoBean(name = "ps1", types = PrintingService.class) [id="CO3-2"][id="CO1-4"][id="CO3-2"](2) public @interface SharedMocks { }
<1> 按类型注册 `OrderService` 和 `UserService` mock。 <1> 按名称注册 `PrintingService` mock。
以下示例演示了如何在测试类上使用 @SharedMocks
。
- Java
-
@SpringJUnitConfig(TestConfig.class) @SharedMocks [id="CO4-1"][id="CO1-5"][id="CO4-1"](1) class BeanOverrideTests { @Autowired OrderService orderService; [id="CO4-2"][id="CO1-6"][id="CO4-2"](2) @Autowired UserService userService; [id="CO4-3"][id="CO1-7"][id="CO4-3"](2) @Autowired PrintingService ps1; [id="CO4-4"][id="CO1-8"][id="CO4-4"](2) // Inject other components that rely on the mocks. @Test void testThatDependsOnMocks() { // ... } }
<1> 通过自定义 `@SharedMocks` 注解注册通用 mock。 <1> 可选注入 mock 以 _桩化_ 或 _验证_ 它们。
这些 mock 也可以注入到 |
@MockitoSpyBean
示例
以下示例展示了如何使用 @MockitoSpyBean
注解的默认行为。
- Java
-
@SpringJUnitConfig(TestConfig.class) class BeanOverrideTests { @MockitoSpyBean [id="CO5-1"][id="CO1-9"][id="CO5-1"](1) CustomService customService; // tests... }
<1> 用 Mockito spy 包装类型为 `CustomService` 的 bean。
在上面的示例中,我们正在包装类型为 CustomService
的 bean。如果存在多个该类型的 bean,则考虑名为 customService
的 bean。否则,测试将失败,您需要提供某种限定符来标识您要监视哪个 CustomService
bean。
以下示例使用按名称查找,而不是按类型查找。
- Java
-
@SpringJUnitConfig(TestConfig.class) class BeanOverrideTests { @MockitoSpyBean("service") [id="CO6-1"][id="CO1-10"][id="CO6-1"](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}) [id="CO7-1"][id="CO1-11"][id="CO7-1"](1) @MockitoSpyBean(name = "ps1", types = PrintingService.class) [id="CO7-2"][id="CO1-12"][id="CO7-2"](2) public @interface SharedSpies { }
<1> 按类型注册 `OrderService` 和 `UserService` spy。 <1> 按名称注册 `PrintingService` spy。
以下示例演示了如何在测试类上使用 @SharedSpies
。
- Java
-
@SpringJUnitConfig(TestConfig.class) @SharedSpies [id="CO8-1"][id="CO1-13"][id="CO8-1"](1) class BeanOverrideTests { @Autowired OrderService orderService; [id="CO8-2"][id="CO1-14"][id="CO8-2"](2) @Autowired UserService userService; [id="CO8-3"][id="CO1-15"][id="CO8-3"](2) @Autowired PrintingService ps1; [id="CO8-4"][id="CO1-16"][id="CO8-4"](2) // Inject other components that rely on the spies. @Test void testThatDependsOnMocks() { // ... } }
<1> 通过自定义 `@SharedSpies` 注解注册通用 spy。 <1> 可选注入 spy 以 _桩化_ 或 _验证_ 它们。
这些 spy 也可以注入到 |