依赖引入
为了简化依赖,直接引入引入SpringBoot POM,但是只用Spring+SpringTest来使用单测
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!-- spring-boot-starter-test已经内置junit,这里是显示引入,表示使用Junit4 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
XML-Based
ContextConfiguration+Xml+Properties+Component-scan
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:beans.xml")
public class SpringJunitTest implements ApplicationContextAware {
}
外部XML可以配置properties文件,或component-scan
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.spring"/>
<context:property-placeholder location="application.properties"/>
<!-- 事务注解 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="grus"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
ContextConfiguration+XML+Properties+事物回滚
@RunWith(SpringJUnit4ClassRunner.class)
@TestPropertySource(locations = {"classpath:spring/config-env.properties"})
@ContextConfiguration(locations = {"classpath*:spring/applicationContext*.xml", "classpath*:springmvc/springmvc-backend.xml"})
@Transactional
@Rollback
public abstact class IntegrationTestBase implements ApplicationContextAware {
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 事务注解 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="grus"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
JavaConfig-Based(零XML)
ContextConfiguration+内部配置类+AnnotationConfigContextLoader
如果使用了AnnotationConfigContextLoader,则需要指定配置类,也就是@Configuration标注的Class
如果ContextConfiguration未指定classes,也就是未使用独立的配置类,则AnnotationConfigContextLoader会从当前类里查找静态内部类作为配置类,如果有则扫描Bean。
注意:当前的静态内部类不能是final,不能是private.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = AnnotationConfigContextLoader.class)
public class SpringJunitTest implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Configuration
static class ExtraConfig {
// this bean will be injected into the OrderServiceTest class
@Bean
public OrderService orderService() {
OrderService orderService = new OrderService();
// set properties, etc.
return orderService;
}
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration() // 走默认的Loader,自动决策
public class SpringJunitTest implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Configuration
static class ExtraConfig {
// this bean will be injected into the OrderServiceTest class
@Bean
public OrderService orderService() {
OrderService orderService = new OrderService();
// set properties, etc.
return orderService;
}
}
}
ContextConfiguration+独立配置类+Loader
指定ContextConfiguration的classes为某个配置类或某些配置类。如果未指定loader,默认为:DelegatingSmartContextLoader,会自动决策. 如果加载的是XML配置,则使用:GenericXmlContextLoader, 如果是配置类,则使用AnnotationConfigContextLoader。
@RunWith(SpringJUnit4ClassRunner.class)
// loader=AnnotationConfigContextLoader 可默认不写
@ContextConfiguration(classes = App.class, loader = AnnotationConfigContextLoader.class)
public class SpringJunitTest implements ApplicationContextAware {
}
@RunWith(SpringJUnit4ClassRunner.class)
// loader=AnnotationConfigContextLoader 可默认不写, 走自动识别Loader
@ContextConfiguration(classes = App.class)
public class SpringJunitTest implements ApplicationContextAware {
}
@ComponentScan(basePackages = {"com.spring"})
@Configuration
public class App {
}
独立配置类,与JavaConfig用法一致,可使用@ComponentScan,@Import, @ImportResource.
当然不建议Import XML文件,因为推荐使用零配置,都采用注解风格。
@ComponentScan(basePackages = {"com.spring"})
@Configuration
@ImportResource("classpath:app.xml")
@Import(User.class)
public class App {
}
ContextConfiguration+配置继承
XML-Based
@ContextConfiguration("base-context.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class BaseTest {
// ...
}
@ContextConfiguration("extended-context.xml")
public class ExtendedTest extends BaseTest {
// ...
}
JavaConfig-Based
@ContextConfiguration(classes=BaseConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class BaseTest {
// ...
}
@ContextConfiguration(classes=ExtendedConfig.class)
public class ExtendedTest extends BaseTest {
// ...
}
ContextConfiguration+Profile
XML-Based
使用@ActiveProfiles
@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
}
}
<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>
JavaConfig-Based
@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
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();
}
}
测试类
package com.bank.service;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader=AnnotationConfigContextLoader.class,
classes={TransferServiceConfig.class, StandaloneDataConfig.class, JndiDataConfig.class})
@ActiveProfiles("dev")
public class TransferServiceTest {
@Autowired
private TransferService transferService;
@Test
public void testTransferService() {
// test the transferService
}
}