测试中的 Bean 覆盖

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

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

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 properties 文件 中注册了后两个(BeanOverrideContextCustomizerFactoryBeanOverrideTestExecutionListener)的实现。

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

内部的 BeanOverrideBeanFactoryPostProcessor 然后使用 Bean 覆盖处理程序,通过创建、替换或包装 Bean 来修改测试的 ApplicationContext,具体取决于相应的 BeanOverrideStrategy

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 名称。