Skip to content

Commit 6a81de9

Browse files
committed
Merge branch '6.2.x'
2 parents 2c749eb + 9181cce commit 6a81de9

39 files changed

+1395
-144
lines changed

framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-mockitobean.adoc

+115-27
Original file line numberDiff line numberDiff line change
@@ -11,29 +11,21 @@ If multiple candidates match, `@Qualifier` can be provided to narrow the candida
1111
override. Alternatively, a candidate whose bean name matches the name of the field will
1212
match.
1313

14-
When using `@MockitoBean`, a new bean will be created if a corresponding bean does not
15-
exist. However, if you would like for the test to fail when a corresponding bean does not
16-
exist, you can set the `enforceOverride` attribute to `true` – for example,
17-
`@MockitoBean(enforceOverride = true)`.
18-
19-
To use a by-name override rather than a by-type override, specify the `name` attribute
20-
of the annotation.
21-
2214
[WARNING]
2315
====
2416
Qualifiers, including the name of the field, are used to determine if a separate
2517
`ApplicationContext` needs to be created. If you are using this feature to mock or spy
26-
the same bean in several tests, make sure to name the field consistently to avoid
18+
the same bean in several test classes, make sure to name the field consistently to avoid
2719
creating unnecessary contexts.
2820
====
2921

30-
Each annotation also defines Mockito-specific attributes to fine-tune the mocking details.
22+
Each annotation also defines Mockito-specific attributes to fine-tune the mocking behavior.
3123

32-
By default, the `@MockitoBean` annotation uses the `REPLACE_OR_CREATE`
24+
The `@MockitoBean` annotation uses the `REPLACE_OR_CREATE`
3325
xref:testing/testcontext-framework/bean-overriding.adoc#testcontext-bean-overriding-custom[strategy for test bean overriding].
34-
If no existing bean matches, a new bean is created on the fly. As mentioned previously,
35-
you can switch to the `REPLACE` strategy by setting the `enforceOverride` attribute to
36-
`true`.
26+
If no existing bean matches, a new bean is created on the fly. However, you can switch to
27+
the `REPLACE` strategy by setting the `enforceOverride` attribute to `true`. See the
28+
following section for an example.
3729

3830
The `@MockitoSpyBean` annotation uses the `WRAP`
3931
xref:testing/testcontext-framework/bean-overriding.adoc#testcontext-bean-overriding-custom[strategy],
@@ -61,6 +53,17 @@ Such fields can therefore be `public`, `protected`, package-private (default vis
6153
or `private` depending on the needs or coding practices of the project.
6254
====
6355

56+
[[spring-testing-annotation-beanoverriding-mockitobean-examples]]
57+
== `@MockitoBean` Examples
58+
59+
When using `@MockitoBean`, a new bean will be created if a corresponding bean does not
60+
exist. However, if you would like for the test to fail when a corresponding bean does not
61+
exist, you can set the `enforceOverride` attribute to `true` – for example,
62+
`@MockitoBean(enforceOverride = true)`.
63+
64+
To use a by-name override rather than a by-type override, specify the `name` (or `value`)
65+
attribute of the annotation.
66+
6467
The following example shows how to use the default behavior of the `@MockitoBean` annotation:
6568

6669
[tabs]
@@ -69,11 +72,13 @@ Java::
6972
+
7073
[source,java,indent=0,subs="verbatim,quotes"]
7174
----
72-
class OverrideBeanTests {
75+
@SpringJUnitConfig(TestConfig.class)
76+
class BeanOverrideTests {
77+
7378
@MockitoBean // <1>
7479
CustomService customService;
7580
76-
// test case body...
81+
// tests...
7782
}
7883
----
7984
<1> Replace the bean with type `CustomService` with a Mockito `mock`.
@@ -82,8 +87,8 @@ Java::
8287
In the example above, we are creating a mock for `CustomService`. If more than one bean
8388
of that type exists, the bean named `customService` is considered. Otherwise, the test
8489
will fail, and you will need to provide a qualifier of some sort to identify which of the
85-
`CustomService` beans you want to override. If no such bean exists, a bean definition
86-
will be created with an auto-generated bean name.
90+
`CustomService` beans you want to override. If no such bean exists, a bean will be
91+
created with an auto-generated bean name.
8792

8893
The following example uses a by-name lookup, rather than a by-type lookup:
8994

@@ -93,32 +98,114 @@ Java::
9398
+
9499
[source,java,indent=0,subs="verbatim,quotes"]
95100
----
96-
class OverrideBeanTests {
101+
@SpringJUnitConfig(TestConfig.class)
102+
class BeanOverrideTests {
103+
97104
@MockitoBean("service") // <1>
98105
CustomService customService;
99106
100-
// test case body...
107+
// tests...
101108
102109
}
103110
----
104111
<1> Replace the bean named `service` with a Mockito `mock`.
105112
======
106113

107-
If no bean definition named `service` exists, one is created.
114+
If no bean named `service` exists, one is created.
115+
116+
`@MockitoBean` can also be used at the type level:
117+
118+
- on a test class or any superclass or implemented interface in the type hierarchy above
119+
the test class
120+
- on an enclosing class for a `@Nested` test class or on any class or interface in the
121+
type hierarchy or enclosing class hierarchy above the `@Nested` test class
108122

109-
The following example shows how to use the default behavior of the `@MockitoSpyBean` annotation:
123+
When `@MockitoBean` is declared at the type level, the type of bean (or beans) to mock
124+
must be supplied via the `types` attribute – for example,
125+
`@MockitoBean(types = {OrderService.class, UserService.class})`. If multiple candidates
126+
exist in the application context, you can explicitly specify a bean name to mock by
127+
setting the `name` attribute. Note, however, that the `types` attribute must contain a
128+
single type if an explicit bean `name` is configured – for example,
129+
`@MockitoBean(name = "ps1", types = PrintingService.class)`.
130+
131+
To support reuse of mock configuration, `@MockitoBean` may be used as a meta-annotation
132+
to create custom _composed annotations_ — for example, to define common mock
133+
configuration in a single annotation that can be reused across a test suite.
134+
`@MockitoBean` can also be used as a repeatable annotation at the type level — for
135+
example, to mock several beans by name.
136+
137+
The following `@SharedMocks` annotation registers two mocks by-type and one mock by-name.
110138

111139
[tabs]
112140
======
113141
Java::
114142
+
115143
[source,java,indent=0,subs="verbatim,quotes"]
116144
----
117-
class OverrideBeanTests {
145+
@Target(ElementType.TYPE)
146+
@Retention(RetentionPolicy.RUNTIME)
147+
@MockitoBean(types = {OrderService.class, UserService.class}) // <1>
148+
@MockitoBean(name = "ps1", types = PrintingService.class) // <2>
149+
public @interface SharedMocks {
150+
}
151+
----
152+
<1> Register `OrderService` and `UserService` mocks by-type.
153+
<2> Register `PrintingService` mock by-name.
154+
======
155+
156+
The following demonstrates how `@SharedMocks` can be used on a test class.
157+
158+
[tabs]
159+
======
160+
Java::
161+
+
162+
[source,java,indent=0,subs="verbatim,quotes"]
163+
----
164+
@SpringJUnitConfig(TestConfig.class)
165+
@SharedMocks // <1>
166+
class BeanOverrideTests {
167+
168+
@Autowired OrderService orderService; // <2>
169+
170+
@Autowired UserService userService; // <2>
171+
172+
@Autowired PrintingService ps1; // <2>
173+
174+
// Inject other components that rely on the mocks.
175+
176+
@Test
177+
void testThatDependsOnMocks() {
178+
// ...
179+
}
180+
}
181+
----
182+
<1> Register common mocks via the custom `@SharedMocks` annotation.
183+
<2> Optionally inject mocks to _stub_ or _verify_ them.
184+
======
185+
186+
TIP: The mocks can also be injected into `@Configuration` classes or other test-related
187+
components in the `ApplicationContext` in order to configure them with Mockito's stubbing
188+
APIs.
189+
190+
[[spring-testing-annotation-beanoverriding-mockitospybean-examples]]
191+
== `@MockitoSpyBean` Examples
192+
193+
The following example shows how to use the default behavior of the `@MockitoSpyBean`
194+
annotation:
195+
196+
[tabs]
197+
======
198+
Java::
199+
+
200+
[source,java,indent=0,subs="verbatim,quotes"]
201+
----
202+
@SpringJUnitConfig(TestConfig.class)
203+
class BeanOverrideTests {
204+
118205
@MockitoSpyBean // <1>
119206
CustomService customService;
120207
121-
// test case body...
208+
// tests...
122209
}
123210
----
124211
<1> Wrap the bean with type `CustomService` with a Mockito `spy`.
@@ -137,12 +224,13 @@ Java::
137224
+
138225
[source,java,indent=0,subs="verbatim,quotes"]
139226
----
140-
class OverrideBeanTests {
227+
@SpringJUnitConfig(TestConfig.class)
228+
class BeanOverrideTests {
229+
141230
@MockitoSpyBean("service") // <1>
142231
CustomService customService;
143232
144-
// test case body...
145-
233+
// tests...
146234
}
147235
----
148236
<1> Wrap the bean named `service` with a Mockito `spy`.

spring-test/src/main/java/org/springframework/test/context/NestedTestConfiguration.java

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -81,6 +81,9 @@
8181
* <li>{@link ActiveProfiles @ActiveProfiles}</li>
8282
* <li>{@link TestPropertySource @TestPropertySource}</li>
8383
* <li>{@link DynamicPropertySource @DynamicPropertySource}</li>
84+
* <li>{@link org.springframework.test.context.bean.override.convention.TestBean @TestBean}</li>
85+
* <li>{@link org.springframework.test.context.bean.override.mockito.MockitoBean @MockitoBean}</li>
86+
* <li>{@link org.springframework.test.context.bean.override.mockito.MockitoSpyBean @MockitoSpyBean}</li>
8487
* <li>{@link org.springframework.test.annotation.DirtiesContext @DirtiesContext}</li>
8588
* <li>{@link org.springframework.transaction.annotation.Transactional @Transactional}</li>
8689
* <li>{@link org.springframework.test.annotation.Rollback @Rollback}</li>

spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverride.java

+8-4
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,19 @@
2525
import org.springframework.aot.hint.annotation.Reflective;
2626

2727
/**
28-
* Mark a composed annotation as eligible for Bean Override processing.
28+
* Mark a <em>composed annotation</em> as eligible for Bean Override processing.
2929
*
3030
* <p>Specifying this annotation registers the configured {@link BeanOverrideProcessor}
3131
* which must be capable of handling the composed annotation and its attributes.
3232
*
33-
* <p>Since the composed annotation should only be applied to non-static fields, it is
34-
* expected that it is meta-annotated with {@link Target @Target(ElementType.FIELD)}.
33+
* <p>Since the composed annotation will typically only be applied to non-static
34+
* fields, it is expected that the composed annotation is meta-annotated with
35+
* {@link Target @Target(ElementType.FIELD)}. However, certain bean override
36+
* annotations may be declared with an additional {@code ElementType.TYPE} target
37+
* for use at the type level, as is the case for {@code @MockitoBean} which can
38+
* be declared on a field, test class, or test interface.
3539
*
36-
* <p>For concrete examples, see
40+
* <p>For concrete examples of such composed annotations, see
3741
* {@link org.springframework.test.context.bean.override.convention.TestBean @TestBean},
3842
* {@link org.springframework.test.context.bean.override.mockito.MockitoBean @MockitoBean}, and
3943
* {@link org.springframework.test.context.bean.override.mockito.MockitoSpyBean @MockitoSpyBean}.

0 commit comments

Comments
 (0)