目录
Context configuration with XML resources
Context configuration with Groovy scripts
Context configuration with annotated classes
Context configuration with environment profiles
Mixing XML, Groovy scripts, and annotated classes
Context configuration with test property sources
前言
@ContextConfiguration注解归属于Spring Framework 的Spring TestContext Framework章节,其作用是通过加载xml,groovy或@Configuration标注的配置类等配置文件,完成集成测试中ApplicationContext的构建。
Context configuration with XML resources
其背后是通过GenericXmlContextLoader或GenericXmlWebContextLoader完成对xml的加载。
@RunWith(SpringJUnit4ClassRunner.class)
// ApplicationContext will be loaded from "/app-config.xml" and
// "/test-config.xml" in the root of the classpath
@ContextConfiguration(locations={"/app-config.xml", "/test-config.xml"})
public class MyTest {
// class body...
}
Context configuration with Groovy scripts
@RunWith(SpringJUnit4ClassRunner.class)
// ApplicationContext will be loaded from "/AppConfig.groovy" and
// "/TestConfig.groovy" in the root of the classpath
@ContextConfiguration({"/AppConfig.groovy", "/TestConfig.Groovy"})
public class MyTest {
// class body...
}
Context configuration with annotated classes
其背后是通过AnnotationConfigContextLoader或AnnotationConfigWebContextLoader完成对配置类的加载。
1. 配置类可以是内部类
2. 通过@ContextConfiguration与配置类的配合,可以实现同时通过xml,groovy,配置类去构建ApplicationContext。
@RunWith(SpringJUnit4ClassRunner.class)
// ApplicationContext will be loaded from the
// static inner Config class
@ContextConfiguration
public class OrderServiceTest {
@Configuration
static class Config {
// this bean will be injected into the OrderServiceTest class
@Bean
public OrderService orderService() {
OrderService orderService = new OrderServiceImpl();
// set properties, etc.
return orderService;
}
}
@Autowired
private OrderService orderService;
@Test
public void testOrderService() {
// test the orderService
}
}
Context configuration with environment profiles
使用@ActiveProfiles注解也可以帮助构建ApplicationContext,但满足的条件比较苛刻。一般使用maven打包的方式,或者手动读properties配置文件的方式进行分环境的方案,都不适用@ActiveProfiles。
如果是xml形式,使用
<!-- 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 profile="default">
<jdbc:embedded-database id="dataSource">
<jdbc:script
location="classpath:com/bank/config/sql/schema.sql"/>
</jdbc:embedded-database>
</beans>
</beans>
@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
}
}
如果是java代码形式
@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("default")
public class DefaultDataConfig {
@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.HSQL)
.addScript("classpath:com/bank/config/sql/schema.sql")
.build();
}
}
@Configuration
public class TransferServiceConfig {
@Autowired DataSource dataSource;
@Bean
public TransferService transferService() {
return new DefaultTransferService(accountRepository(), feePolicy());
}
@Bean
public AccountRepository accountRepository() {
return new JdbcAccountRepository(dataSource);
}
@Bean
public FeePolicy feePolicy() {
return new ZeroFeePolicy();
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {
TransferServiceConfig.class,
StandaloneDataConfig.class,
JndiDataConfig.class,
DefaultDataConfig.class})
@ActiveProfiles("dev")
public class TransferServiceTest {
@Autowired
private TransferService transferService;
@Test
public void testTransferService() {
// test the transferService
}
}
Mixing XML, Groovy scripts, and annotated classes
@RunWith(SpringJUnit4ClassRunner.class)
// 用@Configuration标注的配置类作为切入点,在配置类上用@ImportResource引入xml文件
@ContextConfiguration(classes = {TestCase.Config.class})
@TestPropertySource(locations = {"classpath:application.properties"})
public class TestCase {
@Autowired
ApplicationContext applicationContext;
@Test
public void testEnvironment() {
String property = applicationContext.getEnvironment().getProperty("jdbc.url");
System.out.println(property);
SpringContextUtils springContextUtils = (SpringContextUtils) applicationContext.getBean("springContextUtils");
System.out.println(springContextUtils);
}
@Configuration
@ImportResource(locations = {"classpath:applicationContext.xml"})
public static class Config{
}
}
Context configuration with test property sources
TestPropertySource注解可以用于引入properties或xml形式的properties文件,并帮助构造ApplicationContext(主要是把properties中的键值对存入enviroment中),其用法包括三种
- 引入xml形式的properties文件
- 引入properties形式的properties文件
- 不引入文件直接定义
1. TestPropertySource注解比PropertySource注解有着更高的优先级,假如同时使用了两个注解引入了相同key但不同value的键值对,@TestPropertySource会将@PropertySource覆盖。
2. 直接定义又比文件引入的形式有着更高的优先级
@ContextConfiguration
@TestPropertySource("/test.properties")
public class MyIntegrationTests {
// class body...
}
@ContextConfiguration
@TestPropertySource(properties = {"timezone = GMT", "port: 4242"})
public class MyIntegrationTests {
// class body...
}