测试中的 Bean 覆盖

测试中的 Bean 覆盖(Bean overriding)是指通过在测试类或测试类中的一个或多个非静态字段上使用注解,来覆盖测试类的 ApplicationContext 中的特定 Bean 的能力。

此功能旨在作为一种风险较低的替代方案,以取代通过 @Bean 注册 Bean 并将 DefaultListableBeanFactorysetAllowBeanDefinitionOverriding 标志设置为 true 的做法。

Spring TestContext 框架提供了两组用于 Bean 覆盖的注解。

前者纯粹依赖于 Spring,而后者则依赖于 Mockito 第三方库。

自定义 Bean 覆盖支持

上面提到的三个注解基于 @BeanOverride 元注解和相关的基础设施构建,这使得可以定义自定义的 Bean 覆盖变体。

要实现自定义 Bean 覆盖支持,需要以下内容:

  • 使用 @BeanOverride 元注解标记的注解,该注解定义了要使用的 BeanOverrideProcessor

  • 一个自定义的 BeanOverrideProcessor 实现

  • 由处理器创建一个或多个具体的 BeanOverrideHandler 实现

Spring TestContext 框架包含对以下 API 的实现,这些 API 支持 Bean 覆盖并负责设置其余基础设施。

  • 一个 BeanFactoryPostProcessor

  • 一个 ContextCustomizerFactory

  • 一个 TestExecutionListener

spring-test 模块在其 META-INF/spring.factories 属性文件中注册了后两者的实现(BeanOverrideContextCustomizerFactoryBeanOverrideTestExecutionListener)。

Bean 覆盖基础设施会搜索测试类上的注解以及测试类中非静态字段上带有 @BeanOverride 元注解的注解,并实例化相应的 BeanOverrideProcessor,该处理器负责创建适当的 BeanOverrideHandler

内部的 BeanOverrideBeanFactoryPostProcessor 然后使用 bean 覆盖处理器,根据相应的 BeanOverrideStrategy 定义,通过创建、替换或包装 bean 来修改测试的 ApplicationContext

REPLACE (替换)

替换 Bean。如果相应的 Bean 不存在,则抛出异常。

REPLACE_OR_CREATE (替换或创建)

如果 Bean 存在则替换。如果相应的 Bean 不存在,则创建新的 Bean。

WRAP (包装)

检索原始 Bean 并对其进行包装。

只有 singleton Bean 可以被覆盖。任何尝试覆盖非 singleton Bean 的行为都将导致异常。

替换由 FactoryBean 创建的 Bean 时,FactoryBean 本身将被替换为由适用的 BeanOverrideHandler 创建的 Bean 覆盖实例所对应的 singleton Bean。

包装由 FactoryBean 创建的 Bean 时,将包装由 FactoryBean 创建的对象,而不是 FactoryBean 本身。

与 Spring 的自动装配机制(例如,解析 @Autowired 字段)相比,TestContext 框架中的 Bean 覆盖基础设施在定位 Bean 时可执行的启发式操作有限。要么 BeanOverrideProcessor 可以计算要覆盖的 Bean 的名称,要么可以根据被注解字段的类型及其限定符注解来明确选择 Bean。

通常,BeanOverrideFactoryPostProcessor 会“按类型”选择 Bean。或者,用户也可以在自定义注解中直接提供 Bean 名称。

BeanOverrideProcessor 实现也可以基于约定或其他方法在内部计算 Bean 名称。