@@ -22,8 +22,19 @@ given level in the hierarchy, the configuration resource type (that is, XML conf
22
22
files or component classes) must be consistent. Otherwise, it is perfectly acceptable to
23
23
have different levels in a context hierarchy configured using different resource types.
24
24
25
- The remaining JUnit Jupiter based examples in this section show common configuration
26
- scenarios for integration tests that require the use of context hierarchies.
25
+ [NOTE]
26
+ ====
27
+ If you use `@DirtiesContext` in a test whose context is configured as part of a context
28
+ hierarchy, you can use the `hierarchyMode` flag to control how the context cache is
29
+ cleared.
30
+
31
+ For further details, see the discussion of `@DirtiesContext` in
32
+ xref:testing/annotations/integration-spring/annotation-dirtiescontext.adoc[Spring Testing Annotations]
33
+ and the {spring-framework-api}/test/annotation/DirtiesContext.html[`@DirtiesContext`] javadoc.
34
+ ====
35
+
36
+ The JUnit Jupiter based examples in this section show common configuration scenarios for
37
+ integration tests that require the use of context hierarchies.
27
38
28
39
**Single test class with context hierarchy**
29
40
--
@@ -229,12 +240,118 @@ Kotlin::
229
240
class ExtendedTests : BaseTests() {}
230
241
----
231
242
======
243
+ --
232
244
233
- .Dirtying a context within a context hierarchy
234
- NOTE: If you use `@DirtiesContext` in a test whose context is configured as part of a
235
- context hierarchy, you can use the `hierarchyMode` flag to control how the context cache
236
- is cleared. For further details, see the discussion of `@DirtiesContext` in
237
- xref:testing/annotations/integration-spring/annotation-dirtiescontext.adoc[Spring Testing Annotations] and the
238
- {spring-framework-api}/test/annotation/DirtiesContext.html[`@DirtiesContext`] javadoc.
245
+ [[testcontext-ctx-management-ctx-hierarchies-with-bean-overrides]]
246
+ **Context hierarchies with bean overrides**
239
247
--
248
+ When `@ContextHierarchy` is used in conjunction with
249
+ xref:testing/testcontext-framework/bean-overriding.adoc[bean overrides] such as
250
+ `@TestBean`, `@MockitoBean`, or `@MockitoSpyBean`, it may be desirable or necessary to
251
+ have the override applied to a single level in the context hierarchy. To achieve that,
252
+ the bean override must specify a context name that matches a name configured via the
253
+ `name` attribute in `@ContextConfiguration`.
254
+
255
+ The following test class configures the name of the second hierarchy level to be
256
+ `"user-config"` and simultaneously specifies that the `UserService` should be wrapped in
257
+ a Mockito spy in the context named `"user-config"`. Consequently, Spring will only
258
+ attempt to create the spy in the `"user-config"` context and will not attempt to create
259
+ the spy in the parent context.
260
+
261
+ [tabs]
262
+ ======
263
+ Java::
264
+ +
265
+ [source,java,indent=0,subs="verbatim,quotes"]
266
+ ----
267
+ @ExtendWith(SpringExtension.class)
268
+ @ContextHierarchy({
269
+ @ContextConfiguration(classes = AppConfig.class),
270
+ @ContextConfiguration(classes = UserConfig.class, name = "user-config")
271
+ })
272
+ class IntegrationTests {
273
+
274
+ @MockitoSpyBean(contextName = "user-config")
275
+ UserService userService;
276
+
277
+ // ...
278
+ }
279
+ ----
280
+
281
+ Kotlin::
282
+ +
283
+ [source,kotlin,indent=0,subs="verbatim,quotes"]
284
+ ----
285
+ @ExtendWith(SpringExtension::class)
286
+ @ContextHierarchy(
287
+ ContextConfiguration(classes = [AppConfig::class]),
288
+ ContextConfiguration(classes = [UserConfig::class], name = "user-config"))
289
+ class IntegrationTests {
290
+
291
+ @MockitoSpyBean(contextName = "user-config")
292
+ lateinit var userService: UserService
293
+
294
+ // ...
295
+ }
296
+ ----
297
+ ======
240
298
299
+ When applying bean overrides in different levels of the context hierarchy, you may need
300
+ to have all of the bean override instances injected into the test class in order to
301
+ interact with them — for example, to configure stubbing for mocks. However, `@Autowired`
302
+ will always inject a matching bean found in the lowest level of the context hierarchy.
303
+ Thus, to inject bean override instances from specific levels in the context hierarchy,
304
+ you need to annotate fields with appropriate bean override annotations and configure the
305
+ name of the context level.
306
+
307
+ The following test class configures the names of the hierarchy levels to be `"parent"`
308
+ and `"child"`. It also declares two `PropertyService` fields that are configured to
309
+ create or replace `PropertyService` beans with Mockito mocks in the respective contexts,
310
+ named `"parent"` and `"child"`. Consequently, the mock from the `"parent"` context will
311
+ be injected into the `propertyServiceInParent` field, and the mock from the `"child"`
312
+ context will be injected into the `propertyServiceInChild` field.
313
+
314
+ [tabs]
315
+ ======
316
+ Java::
317
+ +
318
+ [source,java,indent=0,subs="verbatim,quotes"]
319
+ ----
320
+ @ExtendWith(SpringExtension.class)
321
+ @ContextHierarchy({
322
+ @ContextConfiguration(classes = ParentConfig.class, name = "parent"),
323
+ @ContextConfiguration(classes = ChildConfig.class, name = "child")
324
+ })
325
+ class IntegrationTests {
326
+
327
+ @MockitoBean(contextName = "parent")
328
+ PropertyService propertyServiceInParent;
329
+
330
+ @MockitoBean(contextName = "child")
331
+ PropertyService propertyServiceInChild;
332
+
333
+ // ...
334
+ }
335
+ ----
336
+
337
+ Kotlin::
338
+ +
339
+ [source,kotlin,indent=0,subs="verbatim,quotes"]
340
+ ----
341
+ @ExtendWith(SpringExtension::class)
342
+ @ContextHierarchy(
343
+ ContextConfiguration(classes = [ParentConfig::class], name = "parent"),
344
+ ContextConfiguration(classes = [ChildConfig::class], name = "child"))
345
+ class IntegrationTests {
346
+
347
+ @MockitoBean(contextName = "parent")
348
+ lateinit var propertyServiceInParent: PropertyService
349
+
350
+ @MockitoBean(contextName = "child")
351
+ lateinit var propertyServiceInChild: PropertyService
352
+
353
+ // ...
354
+ }
355
+ ----
356
+ ======
357
+ --
0 commit comments