目录
Spring4.1新特性——综述
Spring4.1新特性——Spring核心部分及其他
Spring4.1新特性——Spring缓存框架增强
Spring4.1新特性——异步调用和事件机制的异常处理
Spring4.1新特性——数据库集成测试脚本初始化
Spring4.1新特性——Spring MVC增强
Spring4.1新特性——页面自动化测试框架Spring MVC Test HtmlUnit简介
Spring4.1新特性——静态资源处理增强
在Spring 4.1之前我们在准备测试数据时可能通过继承AbstractTransactionalJUnit4SpringContextTests,然后调用 executeSqlScript()进行测试,其中存在一个主要问题:如果要同时执行多个数据源的初始化就靠不住了,而且使用起来也不是特别便 利,Spring4.1提供了@Sql注解来完成这个任务。
1、初始化Spring配置:
<jdbc:embedded-database id="dataSource1" type="HSQL"/> <jdbc:embedded-database id="dataSource2" type="HSQL"/> <bean id="txManager1" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource1"/> </bean> <bean id="txManager2" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource2"/> </bean>
此处使用jdbc:embedded嵌入数据库来完成测试,数据库使用HSQL。
2、 方法级别的@Sql
@RunWith(SpringJUnit4ClassRunner.class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@ContextConfiguration(value = "classpath:spring-datasource.xml")
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class MethodLevelSqlTest {
private JdbcTemplate jdbcTemplate1;
private JdbcTemplate jdbcTemplate2;
@Autowired
@Qualifier("dataSource1")
public void setDataSource1(DataSource dataSource1) {
this.jdbcTemplate1 = new JdbcTemplate(dataSource1);
}
@Autowired
@Qualifier("dataSource2")
public void setDataSource2(DataSource dataSource2) {
this.jdbcTemplate2 = new JdbcTemplate(dataSource2);
}
@Test
@Sql(value = {"classpath:schema.sql", "classpath:init-data.sql", "classpath:updated-data.sql"},
config =
@SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",
dataSource = "dataSource1", transactionManager = "txManager1"))
public void test01_simple() {
Assert.assertEquals(
Integer.valueOf(3),
jdbcTemplate1.queryForObject("select count(1) from users", Integer.class));
}
@Test
@Sql(value = {"classpath:schema.sql", "classpath:init-data.sql"},
config =
@SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",
dataSource = "dataSource2", transactionManager = "txManager2"))
public void test02_simple() {
Assert.assertEquals(
Integer.valueOf(2),
jdbcTemplate2.queryForObject("select count(1) from users", Integer.class));
}
} 方法级别的@Sql在每个方法上都会执行。其中@Sql可以指定多个sql文件,然后通过@SqlConfig指定其编码、分隔符、注释前缀、使用哪个数据源和事务管理器。
3、类级别的@Sql
@RunWith(SpringJUnit4ClassRunner.class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@ContextConfiguration(value = "classpath:spring-datasource.xml")
@Sql(value = {"classpath:schema.sql", "classpath:init-data.sql", "classpath:updated-data.sql"},
config =
@SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",
dataSource = "dataSource1", transactionManager = "txManager1"))
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class ClassLevelSqlTest {
private JdbcTemplate jdbcTemplate1;
@Autowired
@Qualifier("dataSource1")
public void setDataSource1(DataSource dataSource1) {
this.jdbcTemplate1 = new JdbcTemplate(dataSource1);
}
@Test
public void test01_simple() {
Assert.assertEquals(
Integer.valueOf(3),
jdbcTemplate1.queryForObject("select count(1) from users", Integer.class));
}
} 类级别的对整个测试用例中的每个方法都起作用。
4、指定多个@Sql
Java8之前需要使用@SqlGroup,而Java8之后直接使用多个@Sql注解即可。
@RunWith(SpringJUnit4ClassRunner.class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@ContextConfiguration(value = "classpath:spring-datasource.xml")
@Transactional()
@SqlGroup(
{
@Sql(value = {"classpath:schema.sql", "classpath:init-data.sql", "classpath:updated-data.sql"},
config =
@SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",
dataSource = "dataSource1", transactionManager = "txManager1")),
@Sql(value = {"classpath:schema.sql", "classpath:init-data.sql"},
config =
@SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",
dataSource = "dataSource2", transactionManager = "txManager2"))
}
)
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class ClassLevelSqlGroupTest {
private JdbcTemplate jdbcTemplate1;
private JdbcTemplate jdbcTemplate2;
@Autowired
@Qualifier("dataSource1")
public void setDataSource1(DataSource dataSource1) {
this.jdbcTemplate1 = new JdbcTemplate(dataSource1);
}
@Autowired
@Qualifier("dataSource2")
public void setDataSource2(DataSource dataSource2) {
this.jdbcTemplate2 = new JdbcTemplate(dataSource2);
}
@Test
@Transactional()
@Sql(value = {"classpath:schema.sql", "classpath:init-data.sql", "classpath:updated-data.sql"},
config =
@SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",
dataSource = "dataSource1", transactionManager = "txManager1"))
public void test01_simple() {
Assert.assertEquals(
Integer.valueOf(3),
jdbcTemplate1.queryForObject("select count(1) from users", Integer.class));
}
@Test
@Transactional()
@Sql(value = {"classpath:schema.sql", "classpath:init-data.sql"},
config =
@SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",
dataSource = "dataSource2", transactionManager = "txManager2"))
public void test02_simple() {
Assert.assertEquals(
Integer.valueOf(2),
jdbcTemplate2.queryForObject("select count(1) from users", Integer.class));
}
} 也可以通过元注解把注解合并:
@SqlGroup(
{
@Sql(value = {"classpath:schema.sql", "classpath:init-data.sql", "classpath:updated-data.sql"},
config =
@SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",
dataSource = "dataSource1", transactionManager = "txManager1")),
@Sql(value = {"classpath:schema.sql", "classpath:init-data.sql"},
config =
@SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",
dataSource = "dataSource2", transactionManager = "txManager2"))
}
)
@Retention(RUNTIME)
@Target(TYPE)
@interface CompositeSqlGroup {
} 直接使用@CompositeSqlGroup注解即可。
5、事务
@RunWith(SpringJUnit4ClassRunner.class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@ContextConfiguration(value = "classpath:spring-datasource.xml")
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class TransactionalTest {
private JdbcTemplate jdbcTemplate1;
private JdbcTemplate jdbcTemplate2;
@Autowired
@Qualifier("dataSource1")
public void setDataSource1(DataSource dataSource1) {
this.jdbcTemplate1 = new JdbcTemplate(dataSource1);
}
@Autowired
@Qualifier("dataSource2")
public void setDataSource2(DataSource dataSource2) {
this.jdbcTemplate2 = new JdbcTemplate(dataSource2);
}
@Test
@Transactional("txManager1")
@Sql(value = {"classpath:schema.sql", "classpath:init-data.sql", "classpath:updated-data.sql"},
config =
@SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",
dataSource = "dataSource1", transactionManager = "txManager1"))
public void test01_simple() {
//判断是在事务中执行
Assert.assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
Assert.assertTrue(TestTransaction.isActive());
Assert.assertEquals(
Integer.valueOf(3),
jdbcTemplate1.queryForObject("select count(1) from users", Integer.class));
}
@Test
@Transactional("txManager2")
@Sql(value = {"classpath:schema.sql", "classpath:init-data.sql"},
config =
@SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",
dataSource = "dataSource2", transactionManager = "txManager2"))
public void test02_simple() {
Assert.assertEquals(
Integer.valueOf(2),
jdbcTemplate2.queryForObject("select count(1) from users", Integer.class));
}
@Test
@Transactional("txManager2")
@Sql(value = {"classpath:schema.sql", "classpath:init-data.sql"},
config =
@SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",
dataSource = "dataSource2", transactionManager = "txManager2"))
public void test03_simple() {
Assert.assertEquals(
Integer.valueOf(2),
jdbcTemplate2.queryForObject("select count(1) from users", Integer.class));
TestTransaction.flagForRollback();
}
@Rule
public TestName testName = new TestName();
@AfterTransaction
public void afterTransaction() {
System.out.println(testName.getMethodName());
if("test03_simple".equals(testName.getMethodName())) {
Assert.assertEquals(
Integer.valueOf(0),
jdbcTemplate2.queryForObject("select count(1) from users", Integer.class));
}
}
} 可以使用//判断是在事务中执行 TransactionSynchronizationManager.isActualTransactionActive()或 TestTransaction.isActive()来判断是否是在事务中执行;通过 TestTransaction.flagForRollback();来回滚事务;在测试用例中@AfterTransaction来断言回滚后数据没 有插入。
相关文章
Spring事务不起作用 问题汇总
如何测试REQUIRES_NEW事务
Spring4新特性
Spring4新特性——泛型限定式依赖注入
Spring4新特性——核心容器的其他改进
Spring4新特性——Web开发的增强
Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC
Spring4新特性——Groovy Bean定义DSL
Spring4新特性——更好的Java泛型操作API
Spring4新特性——JSR310日期API的支持
Spring4新特性——注解、脚本、任务、MVC等其他特性改进
源码下载
https://github.com/zhangkaitao/spring4-1-showcase/tree/master/spring4.1-dbtest