测试中的 Bean 覆盖
测试中的 Bean 覆盖是指通过注解测试类中的一个或多个字段,来覆盖测试类上下文中的特定 bean 的能力。
注意:这旨在作为一种风险较小的替代方案,以此来替代通过 @Bean 注册 bean 并将 StandardBeanFactory 的 setAllowBeanDefinitionOverriding 设置为 true 的做法。
Infra 测试框架提供了下面介绍的两组注解。一组纯粹依赖于 Infra,而第二组则依赖于 Mockito 第三方库。
@TestBean
@TestBean 用于测试类字段,以使用通过按约定命名的静态方法提供的实例来覆盖特定 bean。
默认情况下,bean 名称和关联的静态方法名称派生自被注解的字段名称,但该注解允许提供特定值。
@TestBean 注解使用 REPLACE_DEFINITION 测试 bean 覆盖策略。
以下示例展示了如何完全配置 @TestBean 注解,使用等同于默认值的显式值:
-
Java
class OverrideBeanTests {
@TestBean(name = "service", methodName = "serviceTestOverride") (1)
private CustomService service;
// test case body...
private static CustomService serviceTestOverride() { (2)
return new MyFakeCustomService();
}
}
| 1 | 在此测试类中标记一个字段用于 bean 覆盖 |
| 2 | 此静态方法的结果将用作实例并注入到字段中 |
注意:要调用的方法会在测试类及其可能拥有的任何封闭类以及其层次结构中搜索。这通常允许嵌套测试类依赖于根测试类中使用的方法。
@MockitoBean 和 @MockitoSpyBean
@MockitoBean 和 @MockitoSpyBean 用于测试类字段,分别使用 mock 和 spy 实例覆盖 bean。在后一种情况下,原始 bean 定义不会被替换,而是捕获早期实例并由 spy 包装。
默认情况下,要覆盖的 bean 名称派生自被注解的字段名称,但这两种注解都允许提供特定的 name。每个注解还定义了 Mockito 特定的属性以微调 mock 细节。
@MockitoBean 注解使用 CREATE_OR_REPLACE_DEFINITION 测试 bean 覆盖策略。
@MockitoSpyBean 注解使用 WRAP_EARLY_BEAN 策略,并且原始实例被包装在 Mockito spy 中。
以下示例展示了如何为 @MockitoBean 和 @MockitoSpyBean 注解配置 bean 名称:
-
Java
class OverrideBeanTests {
@MockitoBean(name = "service1") (1)
private CustomService mockService;
@MockitoSpyBean(name = "service2") (2)
private CustomService spyService; (3)
// test case body...
}
| 1 | 将 mockService 标记为此测试类中 bean service1 的 Mockito mock 覆盖 |
| 2 | 将 spyService 标记为此测试类中 bean service2 的 Mockito spy 覆盖 |
| 3 | 两个字段都将注入 Mockito 值(分别为 mock 和 spy) |
使用自定义注解扩展 bean 覆盖
上面介绍的三个注解建立在 @BeanOverride 元注解和相关基础设施之上,允许定义自定义 bean 覆盖变体。
要创建扩展,需要以下内容:
-
一个使用
@BeanOverride元注解的注解,定义要使用的BeanOverrideProcessor。 -
BeanOverrideProcessor实现本身。 -
处理器提供的一个或多个具体
OverrideMetadata实现。
Infra TestContext 框架包含支持 bean 覆盖的基础设施类:BeanFactoryPostProcessor、TestExecutionListener 和 ContextCustomizerFactory。
后两者通过 Infra TestContext 框架 infra.factories 文件自动注册,并负责设置其余的基础设施。
解析测试类以查找任何使用 @BeanOverride 元注解的字段,实例化相关的 BeanOverrideProcessor 以注册 OverrideMetadata。
然后,BeanOverrideBeanFactoryPostProcessor 将使用该信息来更改上下文,根据每个元数据 BeanOverrideStrategy 的定义注册和替换 bean 定义:
-
REPLACE_DEFINITION:替换 bean 定义。如果上下文中不存在,则抛出异常。 -
CREATE_OR_REPLACE_DEFINITION:如果 bean 定义不存在则替换 bean 定义,或者如果不存在则创建一个。 -
WRAP_BEAN:尽早获取原始实例以便将其包装。
注意:Bean 覆盖基础设施不包含任何 bean 解析步骤,这与 @Autowired 注解的字段不同。因此,要覆盖的 bean 的名称必须以某种方式提供给 BeanOverrideProcessor 或由其计算。
通常,用户以某种方式提供名称。