@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 配置它们。