Bean Overriding in Tests

测试中的 bean 重写是指覆盖测试类中 ApplicationContext 的特定 bean 的能力,做法是为测试类中的一个或多个字段添加注解。

Bean overriding in tests refers to the ability to override specific beans in the ApplicationContext for a test class, by annotating one or more fields in the test class.

此功能旨在提供一种降低风险的替代方案,用于通过 @Bean 注册 bean,并将 DefaultListableBeanFactory``setAllowBeanDefinitionOverriding 标志设为 true 的做法。

This feature is intended as a less risky alternative to the practice of registering a bean via @Bean with the DefaultListableBeanFactory setAllowBeanDefinitionOverriding flag set to true.

Spring 测试上下文框架提供了两组 bean 重写注解。

The Spring TestContext framework provides two sets of annotations for bean overriding.

前者完全依赖于 Spring,而后者依赖于 Mockito 第三方库。

The former relies purely on Spring, while the latter set relies on the Mockito third-party library.

Custom Bean Override Support

上面提到的三个注解以 @BeanOverride 元注解和关联的基础设施为基础,它允许人们定义自定义 bean 重写变体。

The three annotations mentioned above build upon the @BeanOverride meta-annotation and associated infrastructure, which allows one to define custom bean overriding variants.

若要创建自定义 bean 重写支持,需要以下内容:

To create custom bean override support, the following is needed:

  • An annotation meta-annotated with @BeanOverride that defines the BeanOverrideProcessor to use

  • A custom BeanOverrideProcessor implementation

  • One or more concrete OverrideMetadata implementations provided by the processor

Spring 测试上下文框架包括支持 bean 重写的以下 API 实现,并负责设置其余的基础设施。

The Spring TestContext framework includes implementations of the following APIs that support bean overriding and are responsible for setting up the rest of the infrastructure.

  • a BeanFactoryPostProcessor

  • a ContextCustomizerFactory

  • a TestExecutionListener

spring-test 模块在其 https://github.com/spring-projects/spring-framework/tree/main/spring-test/src/main/resources/META-INF/spring.factories[META-INF/spring.factories`properties 文件中注册了后两个实现(`BeanOverrideContextCustomizerFactoryBeanOverrideTestExecutionListener)。

The spring-test module registers implementations of the latter two (BeanOverrideContextCustomizerFactory and BeanOverrideTestExecutionListener) in its META-INF/spring.factories properties file.

bean 重写基础设施在测试类中搜索任何使用 @BeanOverride 进行元注解的字段,并实例化负责注册适当 OverrideMetadata 的相应 BeanOverrideProcessor

The bean overriding infrastructure searches in test classes for any field meta-annotated with @BeanOverride and instantiates the corresponding BeanOverrideProcessor which is responsible for registering appropriate OverrideMetadata.

然后,内部 BeanOverrideBeanFactoryPostProcessor 使用该信息,通过注册和替换由相应 BeanOverrideStrategy 定义的 bean 定义,来更改测试的 ApplicationContext

The internal BeanOverrideBeanFactoryPostProcessor then uses that information to alter the test’s ApplicationContext by registering and replacing bean definitions as defined by the corresponding BeanOverrideStrategy:

  • REPLACE_DEFINITION: Replaces the bean definition. Throws an exception if a corresponding bean definition does not exist.

  • REPLACE_OR_CREATE_DEFINITION: Replaces the bean definition if it exists. Creates a new bean definition if a corresponding bean definition does not exist.

  • WRAP_BEAN: Retrieves the original bean instance and wraps it.

然而,与 Spring 的自动装配机制(例如,解析 @Autowired 字段)相反,测试上下文框架中的 bean 重写基础设施在定位 bean 时执行的启发式方法有限。BeanOverrideProcessor 可以计算要重写的 bean 的名称,或者根据带有注解的字段的类型以及它的限定注解明确挑选。

In contrast to Spring’s autowiring mechanism (for example, resolution of an @Autowired field), the bean overriding infrastructure in the TestContext framework has limited heuristics it can perform to locate a bean. Either the BeanOverrideProcessor can compute the name of the bean to override, or it can be unambiguously selected given the type of the annotated field and its qualifying annotations.

通常,BeanOverrideFactoryPostProcessor 根据类型选择 bean。此外,用户可以直接在自定义注解中提供 bean 名称。

Typically, the bean is selected by type by the BeanOverrideFactoryPostProcessor. Alternatively, the user can directly provide the bean name in the custom annotation.

某些 BeanOverrideProcessor 实现还可以基于约定或其他高级方法在内部计算 bean 名称。

Some BeanOverrideProcessor implementations could also internally compute a bean name based on a convention or another advanced method.