From 4171646491096ceb5d11ae9ae4c878c5f552c195 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Mon, 11 Mar 2013 02:26:33 +0100 Subject: [PATCH] Document context hierarchy support in the TCF This commit updates the reference manual regarding the new support for @ContextHierarchy and hierarchy modes in @DirtiesContext. Issue: SPR-10357 --- src/reference/docbook/new-in-3.2.xml | 6 + src/reference/docbook/testing.xml | 375 +++++++++++++++++++++++---- 2 files changed, 326 insertions(+), 55 deletions(-) diff --git a/src/reference/docbook/new-in-3.2.xml b/src/reference/docbook/new-in-3.2.xml index 8d403c6ead9b..dc53ce9777a7 100644 --- a/src/reference/docbook/new-in-3.2.xml +++ b/src/reference/docbook/new-in-3.2.xml @@ -274,6 +274,12 @@ WebApplicationContext in integration tests + + Configuring context hierarchies + in integration tests + + Testing request and session scoped beans diff --git a/src/reference/docbook/testing.xml b/src/reference/docbook/testing.xml index e5bb9aafd784..bb26dc0c5436 100644 --- a/src/reference/docbook/testing.xml +++ b/src/reference/docbook/testing.xml @@ -291,9 +291,9 @@ framework can be configured to reload the configuration and rebuild the application context before executing the next test. - See context management and caching with the TestContext - framework. + See and with the TestContext + framework.
@@ -511,10 +511,9 @@ public class CustomLoaderXmlApplicationContextTests { declared by superclasses by default. - See Context - management and caching and the Javadoc for - @ContextConfiguration for further - details. + See and the + Javadoc for @ContextConfiguration for + further details. @@ -563,6 +562,50 @@ public class WebAppTests { further details. + + + @ContextHierarchy + + A class-level annotation that is used to define a hierarchy of + ApplicationContexts for integration + tests. @ContextHierarchy should be + declared with a list of one or more + @ContextConfiguration instances, each + of which defines a level in the context hierarchy. The following + examples demonstrate the use of + @ContextHierarchy within a single + test class; however, + @ContextHierarchy can also be used + within a test class hierarchy. + + @ContextHierarchy({ + @ContextConfiguration("/parent-config.xml"), + @ContextConfiguration("/child-config.xml") +}) +public class ContextHierarchyTests { + // class body... +} + + @WebAppConfiguration +@ContextHierarchy({ + @ContextConfiguration(classes = AppConfig.class), + @ContextConfiguration(classes = WebConfig.class) +}) +public class WebIntegrationTests { + // class body... +} + + If you need to merge or override the configuration for a given + level of the context hierarchy within a test class hierarchy, you + must explicitly name that level by supplying the same value to the + name attribute in + @ContextConfiguration at each + corresponding level in the class hierarchy. See and the + Javadoc for @ContextHierarchy for + further examples. + + @ActiveProfiles @@ -590,11 +633,9 @@ public class DeveloperIntegrationTests { profiles declared by superclasses by default. - See Context - configuration with environment profiles and the Javadoc for - @ActiveProfiles for examples and - further details. + See + and the Javadoc for @ActiveProfiles + for examples and further details. @@ -603,66 +644,98 @@ public class DeveloperIntegrationTests { Indicates that the underlying Spring ApplicationContext has been - dirtied (i.e., modified or corrupted in some - manner) during the execution of a test and should be closed, - regardless of whether the test passed. - @DirtiesContext is supported in the - following scenarios: + dirtied during the execution of a test (i.e., + modified or corrupted in some manner — for example, by changing the + state of a singleton bean) and should be closed, regardless of + whether the test passed. When an application context is marked + dirty, it is removed from the testing + framework's cache and closed. As a consequence, the underlying + Spring container will be rebuilt for any subsequent test that + requires a context with the same configuration metadata. + + @DirtiesContext can be used as + both a class-level and method-level annotation within the same test + class. In such scenarios, the + ApplicationContext is marked as + dirty after any such annotated method as well + as after the entire class. If the ClassMode + is set to AFTER_EACH_TEST_METHOD, the context is + marked dirty after each test method in the class. + + The following examples explain when the context would be + dirtied for various configuration scenarios: After the current test class, when declared on a class - with class mode set to AFTER_CLASS, which is - the default class mode. + with class mode set to AFTER_CLASS (i.e., the + default class mode). + + @DirtiesContext +public class ContextDirtyingTests { + // some tests that result in the Spring container being dirtied +} After each test method in the current test class, when declared on a class with class mode set to - AFTER_EACH_TEST_METHOD. + AFTER_EACH_TEST_METHOD.@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD) +public class ContextDirtyingTests { + // some tests that result in the Spring container being dirtied +} After the current test, when declared on a method. + + @DirtiesContext +@Test +public void testProcessWhichDirtiesAppCtx() { + // some logic that results in the Spring container being dirtied +} - Use this annotation if a test has modified the context (for - example, by replacing a bean definition). Subsequent tests are - supplied a new context. - - With JUnit 4.5+ or TestNG you can use - @DirtiesContext as both a class-level - and method-level annotation within the same test class. In such - scenarios, the ApplicationContext is - marked as dirty after any such annotated method - as well as after the entire class. If the - ClassMode is set to - AFTER_EACH_TEST_METHOD, the context is marked - dirty after each test method in the class. - - @DirtiesContext -public class ContextDirtyingTests { - // some tests that result in the Spring container being dirtied -} + If @DirtiesContext is used in a + test whose context is configured as part of a context hierarchy via + @ContextHierarchy, the + hierarchyMode flag can be used to control how the + context cache is cleared. By default an + exhaustive algorithm will be used that clears + the context cache including not only the current level but also all + other context hierarchies that share an ancestor context common to + the current test; all + ApplicationContexts that reside in a + sub-hierarchy of the common ancestor context will be removed from + the context cache and closed. If the exhaustive + algorithm is overkill for a particular use case, the simpler + current level algorithm can be specified + instead, as seen below. + + @ContextHierarchy({ + @ContextConfiguration("/parent-config.xml"), + @ContextConfiguration("/child-config.xml") +}) +public class BaseTests { + // class body... +} - @DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD) -public class ContextDirtyingTests { - // some tests that result in the Spring container being dirtied -} +public class ExtendedTests extends BaseTests { - @DirtiesContext -@Test -public void testProcessWhichDirtiesAppCtx() { - // some logic that results in the Spring container being dirtied + @Test + @DirtiesContext(hierarchyMode = HierarchyMode.CURRENT_LEVEL) + public void test() { + // some logic that results in the child context being dirtied + } } - When an application context is marked - dirty, it is removed from the testing - framework's cache and closed; thus the underlying Spring container - is rebuilt for any subsequent test that requires a context with the - same configuration metadata. + For further details regarding the + EXHAUSTIVE and + CURRENT_LEVEL algorithms see the Javadoc for + DirtiesContext.HierarchyMode. @@ -1918,7 +1991,7 @@ public class WacTests { @Configuration classes). - Default Resource Semantics + Default resource semantics @RunWith(SpringJUnit4ClassRunner.class) @@ -1945,7 +2018,7 @@ public class WacTests { locations are classpath based. - Explicit Resource Semantics + Explicit resource semantics @RunWith(SpringJUnit4ClassRunner.class) @@ -2002,7 +2075,7 @@ public class WacTests { ServletTestExecutionListener. - Injecting Mocks + Injecting mocks @WebAppConfiguration @ContextConfiguration @@ -2135,6 +2208,198 @@ public class WacTests { DirtiesContextTestExecutionListener which is enabled by default.
+ +
+ Context hierarchies + + When writing integration tests that rely on a loaded Spring + ApplicationContext, it is often + sufficient to test against a single context; however, there are times + when it is beneficial or even necessary to test against a hierarchy of + ApplicationContexts. For example, if + you are developing a Spring MVC web application you will typically + have a root WebApplicationContext + loaded via Spring's ContextLoaderListener and a + child WebApplicationContext loaded via + Spring's DispatcherServlet. This results in a + parent-child context hierarchy where shared components and + infrastructure configuration are declared in the root context and + consumed in the child context by web-specific components. Another use + case can be found in Spring Batch applications where you often have a + parent context that provides configuration for shared batch + infrastructure and a child context for the configuration of a specific + batch job. + + As of Spring Framework 3.2.2, it is possible to write + integration tests that use context hierarchies by declaring context + configuration via the @ContextHierarchy + annotation, either on an individual test class or within a test class + hierarchy. If a context hierarchy is declared on multiple classes + within a test class hierarchy it is also possible to merge or override + the context configuration for a specific, named level in the context + hierarchy. When merging configuration for a given level in the + hierarchy the configuration resource type (i.e., XML configuration + files or annotated classes) must be consistent; otherwise, it is + perfectly acceptable to have different levels in a context hierarchy + configured using different resource types. + + The following JUnit-based examples demonstrate common + configuration scenarios for integration tests that require the use of + context hierarchies. + + + Single test class with context hierarchy + + ControllerIntegrationTests represents a + typical integration testing scenario for a Spring MVC web + application by declaring a context hierarchy consisting of two + levels, one for the root WebApplicationContext + (loaded using the TestAppConfig + @Configuration class) and one for the + dispatcher servlet + WebApplicationContext (loaded using + the WebConfig + @Configuration class). The + WebApplicationContext that is + autowired into the test instance is the one for + the child context (i.e., the lowest context in the + hierarchy). + + @RunWith(SpringJUnit4ClassRunner.class) +@WebAppConfiguration +@ContextHierarchy({ + @ContextConfiguration(classes = TestAppConfig.class), + @ContextConfiguration(classes = WebConfig.class) +}) +public class ControllerIntegrationTests { + + @Autowired + private WebApplicationContext wac; + + // ... +} + + + + Class hierarchy with implicit parent context + + The following test classes define a context hierarchy within a + test class hierarchy. AbstractWebTests + declares the configuration for a root + WebApplicationContext in a + Spring-powered web application. Note, however, that + AbstractWebTests does not declare + @ContextHierarchy; consequently, + subclasses of AbstractWebTests can optionally + participate in a context hierarchy or simply follow the standard + semantics for @ContextConfiguration. + SoapWebServiceTests and + RestWebServiceTests both extend + AbstractWebTests and define a context + hierarchy via @ContextHierarchy. The + result is that three application contexts will be loaded (one for + each declaration of + @ContextConfiguration), and the + application context loaded based on the configuration in + AbstractWebTests will be set as the parent + context for each of the contexts loaded for the concrete + subclasses. + + @RunWith(SpringJUnit4ClassRunner.class) +@WebAppConfiguration +@ContextConfiguration("file:src/main/webapp/WEB-INF/applicationContext.xml") +public abstract class AbstractWebTests {} + +@ContextHierarchy(@ContextConfiguration("/spring/soap-ws-config.xml") +public class SoapWebServiceTests extends AbstractWebTests {} + +@ContextHierarchy(@ContextConfiguration("/spring/rest-ws-config.xml") +public class RestWebServiceTests extends AbstractWebTests {} + + + + Class hierarchy with merged context hierarchy + configuration + + The following classes demonstrate the use of + named hierarchy levels in order to + merge the configuration for specific levels in + a context hierarchy. BaseTests defines two + levels in the hierarchy, parent and + child. ExtendedTests + extends BaseTests and instructs the Spring + TestContext Framework to merge the context configuration for the + child hierarchy level, simply by ensuring that + the names declared via + ContextConfiguration's + name attribute are both + "child". The result is that three application + contexts will be loaded: one for + "/app-config.xml", one for + "/user-config.xml", and one for + {"/user-config.xml", "/order-config.xml"}. As + with the previous example, the application context loaded from + "/app-config.xml" will be set as the parent + context for the contexts loaded from + "/user-config.xml" and + {"/user-config.xml", "/order-config.xml"}. + + @RunWith(SpringJUnit4ClassRunner.class) +@ContextHierarchy({ + @ContextConfiguration(name = "parent", locations = "/app-config.xml"), + @ContextConfiguration(name = "child", locations = "/user-config.xml") +}) +public class BaseTests {} + +@ContextHierarchy( + @ContextConfiguration(name = "child", locations = "/order-config.xml") +) +public class ExtendedTests extends BaseTests {} + + + + Class hierarchy with overridden context hierarchy + configuration + + In contrast to the previous example, this example demonstrates + how to override the configuration for a given + named level in a context hierarchy by setting + ContextConfiguration's + inheritLocations flag to + false. Consequently, the application context for + ExtendedTests will be loaded only from + "/test-user-config.xml" and will have its parent + set to the context loaded from + "/app-config.xml". + + @RunWith(SpringJUnit4ClassRunner.class) +@ContextHierarchy({ + @ContextConfiguration(name = "parent", locations = "/app-config.xml"), + @ContextConfiguration(name = "child", locations = "/user-config.xml") +}) +public class BaseTests {} + +@ContextHierarchy( + @ContextConfiguration( + name = "child", + locations = "/test-user-config.xml", + inheritLocations = false +)) +public class ExtendedTests extends BaseTests {} + + + + Dirtying a context within a context hierarchy + + If @DirtiesContext is used in a + test whose context is configured as part of a context hierarchy, the + hierarchyMode flag can be used to control how the + context cache is cleared. For further details consult the discussion + of @DirtiesContext in and the Javadoc + for @DirtiesContext. + +