Spring4.1新特性——数据库集成测试

在Spring 4.1之前我们在准备测试数据时可能通过继承AbstractTransactionalJUnit4SpringContextTests,然后调用executeSqlScript()进行测试,其中存在一个主要问题:如果要同时执行多个数据源的初始化就靠不住了,而且使用起来也不是特别便利,Spring4.1提供了@Sql注解来完成这个任务。

 

1、初始化Spring配置: 

Java代码  Spring4.1新特性——数据库集成测试
  1. <jdbc:embedded-database id="dataSource1" type="HSQL"/>  
  2. <jdbc:embedded-database id="dataSource2" type="HSQL"/>  
  3.   
  4. <bean id="txManager1" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
  5.     <property name="dataSource" ref="dataSource1"/>  
  6. </bean>  
  7.   
  8. <bean id="txManager2" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
  9.     <property name="dataSource" ref="dataSource2"/>  
  10. </bean>  

此处使用jdbc:embedded嵌入数据库来完成测试,数据库使用HSQL。

 

2、 方法级别的@Sql

Java代码  Spring4.1新特性——数据库集成测试
  1. @RunWith(SpringJUnit4ClassRunner.class)  
  2. @FixMethodOrder(MethodSorters.NAME_ASCENDING)  
  3. @ContextConfiguration(value = "classpath:spring-datasource.xml")  
  4. @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)  
  5. public class MethodLevelSqlTest {  
  6.     private JdbcTemplate jdbcTemplate1;  
  7.     private JdbcTemplate jdbcTemplate2;  
  8.     @Autowired  
  9.     @Qualifier("dataSource1")  
  10.     public void setDataSource1(DataSource dataSource1) {  
  11.         this.jdbcTemplate1 = new JdbcTemplate(dataSource1);  
  12.     }  
  13.     @Autowired  
  14.     @Qualifier("dataSource2")  
  15.     public void setDataSource2(DataSource dataSource2) {  
  16.         this.jdbcTemplate2 = new JdbcTemplate(dataSource2);  
  17.     }  
  18.   
  19.   
  20.     @Test  
  21.     @Sql(value = {"classpath:schema.sql""classpath:init-data.sql""classpath:updated-data.sql"},  
  22.             config =  
  23.             @SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",  
  24.                     dataSource = "dataSource1", transactionManager = "txManager1"))  
  25.     public void test01_simple() {  
  26.         Assert.assertEquals(  
  27.                 Integer.valueOf(3),  
  28.                 jdbcTemplate1.queryForObject("select count(1) from users", Integer.class));  
  29.     }  
  30.   
  31.   
  32.     @Test  
  33.     @Sql(value = {"classpath:schema.sql""classpath:init-data.sql"},  
  34.             config =  
  35.             @SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",  
  36.                     dataSource = "dataSource2", transactionManager = "txManager2"))  
  37.     public void test02_simple() {  
  38.         Assert.assertEquals(  
  39.                 Integer.valueOf(2),  
  40.                 jdbcTemplate2.queryForObject("select count(1) from users", Integer.class));  
  41.     }  
  42.   
  43. }  

方法级别的@Sql在每个方法上都会执行。其中@Sql可以指定多个sql文件,然后通过@SqlConfig指定其编码、分隔符、注释前缀、使用哪个数据源和事务管理器。

 

 

3、类级别的@Sql

Java代码  Spring4.1新特性——数据库集成测试
  1. @RunWith(SpringJUnit4ClassRunner.class)  
  2. @FixMethodOrder(MethodSorters.NAME_ASCENDING)  
  3. @ContextConfiguration(value = "classpath:spring-datasource.xml")  
  4. @Sql(value = {"classpath:schema.sql""classpath:init-data.sql""classpath:updated-data.sql"},  
  5.         config =  
  6.         @SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",  
  7.                 dataSource = "dataSource1", transactionManager = "txManager1"))  
  8. @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)  
  9. public class ClassLevelSqlTest {  
  10.   
  11.     private JdbcTemplate jdbcTemplate1;  
  12.     @Autowired  
  13.     @Qualifier("dataSource1")  
  14.     public void setDataSource1(DataSource dataSource1) {  
  15.         this.jdbcTemplate1 = new JdbcTemplate(dataSource1);  
  16.     }  
  17.   
  18.     @Test  
  19.     public void test01_simple() {  
  20.         Assert.assertEquals(  
  21.                 Integer.valueOf(3),  
  22.                 jdbcTemplate1.queryForObject("select count(1) from users", Integer.class));  
  23.     }  
  24. }  

类级别的对整个测试用例中的每个方法都起作用。 

 

4、指定多个@Sql 

Java8之前需要使用@SqlGroup,而Java8之后直接使用多个@Sql注解即可。

Java代码  Spring4.1新特性——数据库集成测试
  1. @RunWith(SpringJUnit4ClassRunner.class)  
  2. @FixMethodOrder(MethodSorters.NAME_ASCENDING)  
  3. @ContextConfiguration(value = "classpath:spring-datasource.xml")  
  4. @Transactional()  
  5. @SqlGroup(  
  6.         {  
  7.                 @Sql(value = {"classpath:schema.sql""classpath:init-data.sql""classpath:updated-data.sql"},  
  8.                         config =  
  9.                         @SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",  
  10.                                 dataSource = "dataSource1", transactionManager = "txManager1")),  
  11.                 @Sql(value = {"classpath:schema.sql""classpath:init-data.sql"},  
  12.                         config =  
  13.                         @SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",  
  14.                                 dataSource = "dataSource2", transactionManager = "txManager2"))  
  15.         }  
  16. )  
  17.   
  18. @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)  
  19. public class ClassLevelSqlGroupTest {  
  20.   
  21.     private JdbcTemplate jdbcTemplate1;  
  22.     private JdbcTemplate jdbcTemplate2;  
  23.     @Autowired  
  24.     @Qualifier("dataSource1")  
  25.     public void setDataSource1(DataSource dataSource1) {  
  26.         this.jdbcTemplate1 = new JdbcTemplate(dataSource1);  
  27.     }  
  28.     @Autowired  
  29.     @Qualifier("dataSource2")  
  30.     public void setDataSource2(DataSource dataSource2) {  
  31.         this.jdbcTemplate2 = new JdbcTemplate(dataSource2);  
  32.     }  
  33.   
  34.   
  35.     @Test  
  36.     @Transactional()  
  37.     @Sql(value = {"classpath:schema.sql""classpath:init-data.sql""classpath:updated-data.sql"},  
  38.             config =  
  39.             @SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",  
  40.                     dataSource = "dataSource1", transactionManager = "txManager1"))  
  41.     public void test01_simple() {  
  42.         Assert.assertEquals(  
  43.                 Integer.valueOf(3),  
  44.                 jdbcTemplate1.queryForObject("select count(1) from users", Integer.class));  
  45.     }  
  46.   
  47.   
  48.     @Test  
  49.     @Transactional()  
  50.     @Sql(value = {"classpath:schema.sql""classpath:init-data.sql"},  
  51.             config =  
  52.             @SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",  
  53.                     dataSource = "dataSource2", transactionManager = "txManager2"))  
  54.     public void test02_simple() {  
  55.         Assert.assertEquals(  
  56.                 Integer.valueOf(2),  
  57.                 jdbcTemplate2.queryForObject("select count(1) from users", Integer.class));  
  58.     }  
  59.   
  60. }  

 

也可以通过元注解把注解合并:

Java代码  Spring4.1新特性——数据库集成测试
  1. @SqlGroup(  
  2.         {  
  3.                 @Sql(value = {"classpath:schema.sql""classpath:init-data.sql""classpath:updated-data.sql"},  
  4.                         config =  
  5.                         @SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",  
  6.                                 dataSource = "dataSource1", transactionManager = "txManager1")),  
  7.                 @Sql(value = {"classpath:schema.sql""classpath:init-data.sql"},  
  8.                         config =  
  9.                         @SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",  
  10.                                 dataSource = "dataSource2", transactionManager = "txManager2"))  
  11.         }  
  12. )  
  13. @Retention(RUNTIME)  
  14. @Target(TYPE)  
  15. @interface CompositeSqlGroup {  
  16. }  

直接使用@CompositeSqlGroup注解即可。

 

5、事务

Java代码  Spring4.1新特性——数据库集成测试
  1. @RunWith(SpringJUnit4ClassRunner.class)  
  2. @FixMethodOrder(MethodSorters.NAME_ASCENDING)  
  3. @ContextConfiguration(value = "classpath:spring-datasource.xml")  
  4. @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)  
  5. public class TransactionalTest {  
  6.     private JdbcTemplate jdbcTemplate1;  
  7.     private JdbcTemplate jdbcTemplate2;  
  8.     @Autowired  
  9.     @Qualifier("dataSource1")  
  10.     public void setDataSource1(DataSource dataSource1) {  
  11.         this.jdbcTemplate1 = new JdbcTemplate(dataSource1);  
  12.     }  
  13.     @Autowired  
  14.     @Qualifier("dataSource2")  
  15.     public void setDataSource2(DataSource dataSource2) {  
  16.         this.jdbcTemplate2 = new JdbcTemplate(dataSource2);  
  17.     }  
  18.   
  19.   
  20.     @Test  
  21.     @Transactional("txManager1")  
  22.     @Sql(value = {"classpath:schema.sql""classpath:init-data.sql""classpath:updated-data.sql"},  
  23.             config =  
  24.             @SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",  
  25.                     dataSource = "dataSource1", transactionManager = "txManager1"))  
  26.     public void test01_simple() {  
  27.         //判断是在事务中执行  
  28.         Assert.assertTrue(TransactionSynchronizationManager.isActualTransactionActive());  
  29.         Assert.assertTrue(TestTransaction.isActive());  
  30.         Assert.assertEquals(  
  31.                 Integer.valueOf(3),  
  32.                 jdbcTemplate1.queryForObject("select count(1) from users", Integer.class));  
  33.     }  
  34.   
  35.   
  36.     @Test  
  37.     @Transactional("txManager2")  
  38.     @Sql(value = {"classpath:schema.sql""classpath:init-data.sql"},  
  39.             config =  
  40.             @SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",  
  41.                     dataSource = "dataSource2", transactionManager = "txManager2"))  
  42.     public void test02_simple() {  
  43.         Assert.assertEquals(  
  44.                 Integer.valueOf(2),  
  45.                 jdbcTemplate2.queryForObject("select count(1) from users", Integer.class));  
  46.     }  
  47.   
  48.   
  49.     @Test  
  50.     @Transactional("txManager2")  
  51.     @Sql(value = {"classpath:schema.sql""classpath:init-data.sql"},  
  52.             config =  
  53.             @SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",  
  54.                     dataSource = "dataSource2", transactionManager = "txManager2"))  
  55.     public void test03_simple() {  
  56.         Assert.assertEquals(  
  57.                 Integer.valueOf(2),  
  58.                 jdbcTemplate2.queryForObject("select count(1) from users", Integer.class));  
  59.         TestTransaction.flagForRollback();  
  60.     }  
  61.   
  62.     @Rule  
  63.     public TestName testName = new TestName();  
  64.     @AfterTransaction  
  65.     public void afterTransaction() {  
  66.         System.out.println(testName.getMethodName());  
  67.         if("test03_simple".equals(testName.getMethodName())) {  
  68.             Assert.assertEquals(  
  69.                     Integer.valueOf(0),  
  70.                     jdbcTemplate2.queryForObject("select count(1) from users", Integer.class));  
  71.         }  
  72.     }  
  73. }  

可以使用//判断是在事务中执行TransactionSynchronizationManager.isActualTransactionActive()或TestTransaction.isActive()来判断是否是在事务中执行;通过TestTransaction.flagForRollback();来回滚事务;在测试用例中@AfterTransaction来断言回滚后数据没有插入。


本文转自http://jinnianshilongnian.iteye.com/blog/2106184

上一篇:CSS Stylus(二)


下一篇:使用 Java 11 安装 SAP Commerce Cloud 1905 的一些常见问题