Relax singleton enforcement for Bean Overrides in the TestContext framework

In gh-33602, we introduced strict singleton enforcement for bean
overrides -- for example, for @⁠MockitoBean, @⁠TestBean, etc. However,
the use of BeanFactory#isSingleton(beanName) can result in a
BeanCreationException for certain beans, such as a Spring Data JPA
FactoryBean for a JpaRepository.

In light of that, this commit relaxes the singleton enforcement in
BeanOverrideBeanFactoryPostProcessor by only checking the result of
BeanDefinition#isSingleton() for existing bean definitions.

This commit also updates the Javadoc and reference documentation to
reflect the status quo.

See gh-33602
Closes gh-33800
This commit is contained in:
Sam Brannen
2024-10-28 11:42:56 +01:00
parent 52e813d0ad
commit 81d89f478a
8 changed files with 69 additions and 27 deletions

View File

@@ -39,8 +39,17 @@ xref:testing/testcontext-framework/bean-overriding.adoc#testcontext-bean-overrid
and the original instance is wrapped in a Mockito spy. This strategy requires that
exactly one candidate bean exists.
NOTE: Only _singleton_ beans can be overridden. Any attempt to override a non-singleton
bean will result in an exception.
[TIP]
====
Only _singleton_ beans can be overridden. Any attempt to override a non-singleton bean
will result in an exception.
When using `@MockitoBean` to mock a bean created by a `FactoryBean`, the `FactoryBean`
will be replaced with a singleton mock of the type of object created by the `FactoryBean`.
When using `@MockitoSpyBean` to create a spy for a `FactoryBean`, a spy will be created
for the object created by the `FactoryBean`, not for the `FactoryBean` itself.
====
The following example shows how to use the default behavior of the `@MockitoBean` annotation:

View File

@@ -82,7 +82,7 @@ Java::
<2> The result of this static method will be used as the instance and injected into the field.
======
[NOTE]
[TIP]
====
Spring searches for the factory method to invoke in the test class, in the test class
hierarchy, and in the enclosing class hierarchy for a `@Nested` test class.
@@ -92,5 +92,12 @@ fully-qualified method name following the syntax `<fully-qualified class name>#<
for example, `methodName = "org.example.TestUtils#createCustomService"`.
====
NOTE: Only _singleton_ beans can be overridden. Any attempt to override a non-singleton
bean will result in an exception.
[TIP]
====
Only _singleton_ beans can be overridden. Any attempt to override a non-singleton bean
will result in an exception.
When overriding a bean created by a `FactoryBean`, the `FactoryBean` will be replaced
with a singleton bean corresponding to the value returned from the `@TestBean` factory
method.
====

View File

@@ -57,6 +57,19 @@ defined by the corresponding `BeanOverrideStrategy`:
`WRAP`::
Retrieves the original bean and wraps it.
[TIP]
====
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.
====
[NOTE]
====
In contrast to Spring's autowiring mechanism (for example, resolution of an `@Autowired`
@@ -71,6 +84,3 @@ Alternatively, the user can directly provide the bean name in the custom annotat
`BeanOverrideProcessor` implementations may also internally compute a bean name based on
a convention or some other method.
====
NOTE: Only _singleton_ beans can be overridden. Any attempt to override a non-singleton
bean will result in an exception.