@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.