Use the field name as a fallback qualifier for Bean Overriding
This commit harmonizes how a candidate bean definition is determined for overriding using `@TestBean`, `@MockitoBean`, and `@MockitoSpyBean`. Previously, a qualifier was necessary even if the name of the annotated field matches the name of a candidate. After this commit, such candidate will be picked up transparently, the same it is done for regular autowiring. This commit also reviews the documentation of the feature as considering the field means that its name is taken into account to compute a cache key if by-type lookup is requested. Closes gh-32939
This commit is contained in:
@@ -7,17 +7,27 @@ case, the original bean definition is not replaced, but instead an early instanc
|
||||
bean is captured and wrapped by the spy.
|
||||
|
||||
By default, the annotated field's type is used to search for candidate definitions to
|
||||
override, but note that `@Qualifier` annotations are also taken into account for the
|
||||
purpose of matching. Users can also make things entirely explicit by specifying a bean
|
||||
`name` in the annotation.
|
||||
override. If multiple candidates match, the usual `@Qualifier` can be provided to
|
||||
narrow the candidate to override. Alternatively, a candidate whose bean definition name
|
||||
matches the name of the field will match.
|
||||
|
||||
To use a by-name override rather than a by-type override, specify the `name` attribute
|
||||
of the annotation.
|
||||
|
||||
[WARNING]
|
||||
====
|
||||
The qualifiers, including the name of the field are used to determine if a separate
|
||||
`ApplicationContext` needs to be created. If you are using this feature to mock or
|
||||
spy the same bean in several tests, make sure to name the field consistently to avoid
|
||||
creating unnecessary contexts.
|
||||
====
|
||||
|
||||
Each annotation also defines Mockito-specific attributes to fine-tune the mocking details.
|
||||
|
||||
The `@MockitoBean` annotation uses the `REPLACE_OR_CREATE_DEFINITION`
|
||||
xref:testing/testcontext-framework/bean-overriding.adoc#testcontext-bean-overriding-custom[strategy for test bean overriding].
|
||||
|
||||
It requires that at most one matching candidate definition exists if a bean name
|
||||
is specified, or exactly one if no bean name is specified.
|
||||
If no definition matches, then a definition is created on-the-fly.
|
||||
|
||||
The `@MockitoSpyBean` annotation uses the `WRAP_BEAN`
|
||||
xref:testing/testcontext-framework/bean-overriding.adoc#testcontext-bean-overriding-custom[strategy],
|
||||
@@ -25,8 +35,7 @@ and the original instance is wrapped in a Mockito spy.
|
||||
|
||||
It requires that exactly one candidate definition exists.
|
||||
|
||||
The following example shows how to configure the bean name via `@MockitoBean` and
|
||||
`@MockitoSpyBean`:
|
||||
The following example shows how to use the default behavior of the `@MockitoBean` annotation:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
@@ -35,17 +44,80 @@ Java::
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
----
|
||||
class OverrideBeanTests {
|
||||
|
||||
@MockitoBean(name = "service1") // <1>
|
||||
private CustomService mockService;
|
||||
|
||||
@MockitoSpyBean(name = "service2") // <2>
|
||||
private CustomService spyService; // <3>
|
||||
@MockitoBean // <1>
|
||||
private CustomService customService;
|
||||
|
||||
// test case body...
|
||||
}
|
||||
----
|
||||
<1> Mark `mockService` as a Mockito mock override of bean `service1` in this test class.
|
||||
<2> Mark `spyService` as a Mockito spy override of bean `service2` in this test class.
|
||||
<3> The fields will be injected with the Mockito mock and spy, respectively.
|
||||
<1> Replace the bean with type `CustomService` with a Mockito `mock`.
|
||||
======
|
||||
|
||||
In the example above, we are creating a mock for `CustomService`. If more that
|
||||
one bean with such type exist, the bean named `customService` is considered. Otherwise,
|
||||
the test will fail and you will need to provide a qualifier of some sort to identify which
|
||||
of the `CustomService` beans you want to override. If no such bean exists, a bean
|
||||
definition will be created with an auto-generated bean name.
|
||||
|
||||
The following example uses a by-name lookup, rather than a by-type lookup:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
----
|
||||
class OverrideBeanTests {
|
||||
@MockitoBean(name = "service") // <1>
|
||||
private CustomService customService;
|
||||
|
||||
// test case body...
|
||||
|
||||
}
|
||||
----
|
||||
<1> Replace the bean named `service` with a Mockito `mock`.
|
||||
======
|
||||
|
||||
If no bean definition named `service` exists, one is created.
|
||||
|
||||
The following example shows how to use the default behavior of the `@MockitoSpyBean` annotation:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
----
|
||||
class OverrideBeanTests {
|
||||
@MockitoSpyBean // <1>
|
||||
private CustomService customService;
|
||||
|
||||
// test case body...
|
||||
}
|
||||
----
|
||||
<1> Wrap the bean with type `CustomService` with a Mockito `spy`.
|
||||
======
|
||||
|
||||
In the example above, we are wrapping the bean with type `CustomService`. If more that
|
||||
one bean with such type exist, the bean named `customService` is considered. Otherwise,
|
||||
the test will fail and you will need to provide a qualifier of some sort to identify which
|
||||
of the `CustomService` beans you want to spy.
|
||||
|
||||
The following example uses a by-name lookup, rather than a by-type lookup:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
----
|
||||
class OverrideBeanTests {
|
||||
@MockitoSpyBean(name = "service") // <1>
|
||||
private CustomService customService;
|
||||
|
||||
// test case body...
|
||||
|
||||
}
|
||||
----
|
||||
<1> Wrap the bean named `service` with a Mockito `spy`.
|
||||
======
|
||||
|
||||
@@ -11,11 +11,21 @@ with the type of the bean to override is expected. To make things more explicit,
|
||||
you'd rather use a different name, the annotation allows for a specific method name to
|
||||
be provided.
|
||||
|
||||
By default, the annotated field's type is used to search for candidate definitions to
|
||||
override. If multiple candidates match, the usual `@Qualifier` can be provided to
|
||||
narrow the candidate to override. Alternatively, a candidate whose bean definition name
|
||||
matches the name of the field will match.
|
||||
|
||||
By default, the annotated field's type is used to search for candidate definitions to override.
|
||||
In that case it is required that exactly one definition matches, but note that `@Qualifier`
|
||||
annotations are also taken into account for the purpose of matching.
|
||||
Users can also make things entirely explicit by specifying a bean `name` in the annotation.
|
||||
To use a by-name override rather than a by-type override, specify the `name` attribute
|
||||
of the annotation.
|
||||
|
||||
[WARNING]
|
||||
====
|
||||
The qualifiers, including the name of the field are used to determine if a separate
|
||||
`ApplicationContext` needs to be created. If you are using this feature to override
|
||||
the same bean in several tests, make sure to name the field consistently to avoid
|
||||
creating unnecessary contexts.
|
||||
====
|
||||
|
||||
The following example shows how to use the default behavior of the `@TestBean` annotation:
|
||||
|
||||
@@ -27,11 +37,11 @@ Java::
|
||||
----
|
||||
class OverrideBeanTests {
|
||||
@TestBean // <1>
|
||||
private CustomService service;
|
||||
private CustomService customService;
|
||||
|
||||
// test case body...
|
||||
|
||||
private static CustomService service() { // <2>
|
||||
private static CustomService customService() { // <2>
|
||||
return new MyFakeCustomService();
|
||||
}
|
||||
}
|
||||
@@ -40,8 +50,13 @@ Java::
|
||||
<2> The result of this static method will be used as the instance and injected into the field.
|
||||
======
|
||||
|
||||
In the example above, we are overriding the bean with type `CustomService`. If more that
|
||||
one bean with such type exist, the bean named `customService` is considered. Otherwise,
|
||||
the test will fail and you will need to provide a qualifier of some sort to identify which
|
||||
of the `CustomService` beans you want to override.
|
||||
|
||||
The following example shows how to fully configure the `@TestBean` annotation:
|
||||
|
||||
The following example uses a by-name lookup, rather than a by-type lookup:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
@@ -51,7 +66,7 @@ Java::
|
||||
----
|
||||
class OverrideBeanTests {
|
||||
@TestBean(name = "service", methodName = "createCustomService") // <1>
|
||||
private CustomService service;
|
||||
private CustomService customService;
|
||||
|
||||
// test case body...
|
||||
|
||||
|
||||
Reference in New Issue
Block a user