From 027c25d823267a438f57b3779f9f8fea18d7f803 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Tue, 11 Oct 2011 23:05:28 +0000 Subject: [PATCH] [SPR-8401] Documented TestContext support for @ActiveProfiles in the reference manual. --- spring-framework-reference/src/testing.xml | 204 +++++++++++++++++++-- 1 file changed, 192 insertions(+), 12 deletions(-) diff --git a/spring-framework-reference/src/testing.xml b/spring-framework-reference/src/testing.xml index eb1be21a6b8..6c827acfc66 100644 --- a/spring-framework-reference/src/testing.xml +++ b/spring-framework-reference/src/testing.xml @@ -1059,7 +1059,7 @@ public void testProcessRepeatedly() {
- Context management and caching + Context management Each TestContext provides context management and caching support for the test instance it is responsible @@ -1267,14 +1267,15 @@ public class OrderServiceTest { linkend="integration-testing-annotations-spring" /> the TestContext framework does not allow you to declare both via @ContextConfiguration, but this - does not mean that you cannot use both. If you want to use XML - and + does not mean that you cannot use both. + + If you want to use XML and @Configuration classes to configure your tests, you will have to pick one as the entry point, and that one will have to include or import the other. For example, in XML you can include - @Configuration classes in component - scanning or define them as normal Spring beans; whereas, in a + @Configuration classes via component + scanning or define them as normal Spring beans in XML; whereas, in a @Configuration class you can use @ImportResource to import XML configuration files. Note that this behavior is semantically @@ -1283,8 +1284,8 @@ public class OrderServiceTest { resource locations or a set of @Configuration classes that your production ApplicationContext will - load, but you still have the freedom to include or import the other - type of configuration. + loaded from, but you still have the freedom to include or import the + other type of configuration.
@@ -1357,6 +1358,184 @@ public class ExtendedTest extends BaseTest { }
+
+ Context configuration with environment profiles + + Spring 3.1 introduces first-class support in the framework for + the notion of environments and profiles (a.k.a., bean definition + profiles), and integration tests can now be configured to activate + particular bean definition profiles for various testing scenarios. + This is achieved by annotating a test class with the new + @ActiveProfiles annotation and supplying a list of profiles that + should be activated when loading the ApplicationContext for the + test. + + + @ActiveProfiles may be used with any implementation of the + new SmartContextLoader SPI, but @ActiveProfiles is not supported + with implementations of the older ContextLoader SPI. + + + Let's take a look at some examples with XML configuration and + @Configuration classes. + + <!-- app-config.xml --> +<beans xmlns="http://www.springframework.org/schema/beans" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:jdbc="http://www.springframework.org/schema/jdbc" + xmlns:jee="http://www.springframework.org/schema/jee" + xsi:schemaLocation="..."> + + <bean id="transferService" + class="com.bank.service.internal.DefaultTransferService"> + <constructor-arg ref="accountRepository"/> + <constructor-arg ref="feePolicy"/> + </bean> + + <bean id="accountRepository" + class="com.bank.repository.internal.JdbcAccountRepository"> + <constructor-arg ref="dataSource"/> + </bean> + + <bean id="feePolicy" + class="com.bank.service.internal.ZeroFeePolicy"/> + + <beans profile="dev"> + <jdbc:embedded-database id="dataSource"> + <jdbc:script + location="classpath:com/bank/config/sql/schema.sql"/> + <jdbc:script + location="classpath:com/bank/config/sql/test-data.sql"/> + </jdbc:embedded-database> + </beans> + + <beans profile="production"> + <jee:jndi-lookup id="dataSource" + jndi-name="java:comp/env/jdbc/datasource"/> + </beans> + +</beans> + + package com.bank.service; + +@RunWith(SpringJUnit4ClassRunner.class) +// ApplicationContext will be loaded from "classpath:/app-config.xml" +@ContextConfiguration("/app-config.xml") +@ActiveProfiles("dev") +public class TransferServiceTest { + + @Autowired + private TransferService transferService; + + @Test + public void testTransferService() { + // test the transferService + } +} + + When TransferServiceTest is run, its ApplicationContext will + be loaded from the app-config.xml configuration file in the root of + the classpath. If you inspect app-config.xml you'll notice that the + accountRepository bean has a dependency on a dataSource bean; + however, dataSource is not defined as a top-level bean. Instead, + dataSource is defined twice: once in the production profile and once + in the dev profile. + + By annotating TransferServiceTest with @ActiveProfiles("dev") + we instruct the Spring TestContext Framework to load the + ApplicationContext with the active profiles set to {"dev"}. As a + result, an embedded database will be created, and the + accountRepository bean will be wired with a reference to the + development DataSource. And that's likely what we want in an + integration test. + + The following code listings demonstrate how to implement the + same configuration and integration test but using @Configuration + classes instead of XML. + + @Configuration +@Profile("dev") +public class StandaloneDataConfig { + + @Bean + public DataSource dataSource() { + return new EmbeddedDatabaseBuilder() + .setType(EmbeddedDatabaseType.HSQL) + .addScript("classpath:com/bank/config/sql/schema.sql") + .addScript("classpath:com/bank/config/sql/test-data.sql") + .build(); + } +} + + @Configuration +@Profile("production") +public class JndiDataConfig { + + @Bean + public DataSource dataSource() throws Exception { + Context ctx = new InitialContext(); + return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource"); + } +} + + @Configuration +@Profile("production") +public class JndiDataConfig { + + @Bean + public DataSource dataSource() throws Exception { + Context ctx = new InitialContext(); + return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource"); + } +} + + package com.bank.service; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration( + classes={ + TransferServiceConfig.class, + StandaloneDataConfig.class, + JndiDataConfig.class}) +@ActiveProfiles("dev") +public class TransferServiceTest { + + @Autowired + private TransferService transferService; + + @Test + public void testTransferService() { + // test the transferService + } +} + + In this variation, we have split the XML configuration into + three independent @Configuration classes: + + + + TransferServiceConfig: acquires a dataSource via + dependency injection using @Autowired + + + + StandaloneDataConfig: defines a dataSource for an embedded + database suitable for developer tests + + + + JndiDataConfig: defines a dataSource that is retrieved + from JNDI in a production environment + + + + As with the XML-based configuration example, we still annotate + TransferServiceTest with @ActiveProfiles("dev"), but this time we + specify all three configuration classes via the + @ContextConfiguration annotation. The body of the test class itself + remains completely unchanged. +
+
Context caching @@ -1364,11 +1543,12 @@ public class ExtendedTest extends BaseTest { ApplicationContext has been loaded for a test it will be reused for all subsequent tests that declare the same - unique context configuration within the same process — for example, - all tests run in a suite within an IDE or all tests run for the same - project with a build framework like Ant or Maven. Thus the setup - cost for loading an application context is incurred only once (per - test suite), and subsequent test execution is much faster. + unique context configuration within the same + process — for example, all tests run in a suite within an IDE or all + tests run for the same project with a build framework like Ant or + Maven. Thus the setup cost for loading an application context is + incurred only once (per test suite), and subsequent test execution + is much faster. In the unlikely case that a test corrupts the application context and requires reloading — for example, by modifying a bean