在测试中覆盖 Bean
在测试中覆盖 Bean 是指通过为测试类或测试类中的一个或多个非静态字段添加注解,来覆盖 ApplicationContext
中的特定 Bean 的能力。
此功能旨在作为通过 @Bean
注册 bean 并将 DefaultListableBeanFactory
的 setAllowBeanDefinitionOverriding
标志设置为 true
的做法的一个风险较小的替代方案。
Spring TestContext 框架提供了两组用于 bean 覆盖的注解。
前者完全依赖于 Spring,而后者依赖于 Mockito 第三方库。
自定义 Bean 覆盖支持
上述三个注解基于 @BeanOverride
元注解和相关基础设施,允许定义自定义的 bean 覆盖变体。
要实现自定义 bean 覆盖支持,需要以下内容:
-
使用
@BeanOverride
进行元注解的注解,该注解定义了要使用的BeanOverrideProcessor
-
一个自定义的
BeanOverrideProcessor
实现 -
由处理器创建的一个或多个具体的
BeanOverrideHandler
实现
Spring TestContext 框架包括以下支持 bean 覆盖的 API 实现,并负责设置其余基础设施。
-
一个
BeanFactoryPostProcessor
-
一个
ContextCustomizerFactory
-
一个
TestExecutionListener
spring-test
模块在其 META-INF/spring.factories properties 文件中注册了后两个实现(BeanOverrideContextCustomizerFactory
和 BeanOverrideTestExecutionListener
)。
bean 覆盖基础设施会在测试类上搜索注解,以及在测试类中被 @BeanOverride
元注解的非静态字段上的注解,并实例化相应的 BeanOverrideProcessor
,该处理器负责创建一个合适的 BeanOverrideHandler
。
内部的 BeanOverrideBeanFactoryPostProcessor
然后使用 bean 覆盖处理器,通过创建、替换或包装由相应的 BeanOverrideStrategy
定义的 bean 来更改测试的 ApplicationContext
:
REPLACE
替换 bean。如果不存在相应的 bean,则抛出异常。
REPLACE_OR_CREATE
如果 bean 存在则替换它。如果不存在相应的 bean,则创建一个新的 bean。
WRAP
检索原始 bean 并对其进行包装。
只有 单例 bean 可以被重写。任何尝试重写非单例 bean 的操作都会导致异常。
当替换由 FactoryBean
创建的 bean 时,FactoryBean
本身将被替换为与由适用的 BeanOverrideHandler
创建的 bean 重写实例相对应的单例 bean。
当包装由 FactoryBean
创建的 bean 时,被包装的是由 FactoryBean
创建的对象,而不是 FactoryBean
本身。
与 Spring 的自动装配机制(例如,解析 @Autowired
字段)相比,TestContext 框架中的 bean 覆盖基础设施在定位 bean 时可以执行的启发式方法有限。BeanOverrideProcessor
可以计算要覆盖的 bean 的名称,或者可以根据注解字段的类型及其限定注解明确选择。
通常,bean 是由 BeanOverrideFactoryPostProcessor
"按类型" 选择的。或者,用户可以在自定义注解中直接提供 bean 名称。
BeanOverrideProcessor
实现还可以根据约定或其他方法在内部计算 bean 名称。