Bean Overriding in Tests

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

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.

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

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

Custom Bean Override Support

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

To implement 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 BeanOverrideHandler implementations created by the processor

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

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

The bean overriding infrastructure searches in test classes for any non-static field that is meta-annotated with @BeanOverride and instantiates the corresponding BeanOverrideProcessor which is responsible for creating an appropriate BeanOverrideHandler.

The internal BeanOverrideBeanFactoryPostProcessor then uses bean override handlers to alter the test’s ApplicationContext by creating, replacing, or wrapping beans as defined by the corresponding BeanOverrideStrategy:

REPLACE

Replaces the bean. Throws an exception if a corresponding bean does not exist.

REPLACE_OR_CREATE

Replaces the bean if it exists. Creates a new bean if a corresponding bean does not exist.

WRAP

Retrieves the original bean and wraps it.

Only singleton beans can be overridden. Any attempt to override a non-singleton bean will result in an exception.

When replacing a bean created by a FactoryBean, the FactoryBean itself will be replaced with a singleton bean corresponding to bean override instance created by the applicable BeanOverrideHandler.

When wrapping a bean created by a FactoryBean, the object created by the FactoryBean will be wrapped, not the FactoryBean itself.

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.

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

BeanOverrideProcessor implementations may also internally compute a bean name based on a convention or some other method.