1. 程式人生 > >Spring4.1新特性——資料庫整合測試

Spring4.1新特性——資料庫整合測試

在Spring 4.1之前我們在準備測試資料時可能通過繼承AbstractTransactionalJUnit4SpringContextTests,然後呼叫executeSqlScript()進行測試,其中存在一個主要問題:如果要同時執行多個數據源的初始化就靠不住了,而且使用起來也不是特別便利,Spring4.1提供了@Sql註解來完成這個任務。

1、初始化Spring配置: 

Java程式碼  收藏程式碼
  1. <jdbc:embedded-database id="dataSource1" type="HSQL"/>  
  2. <jdbc:embedded-database id="dataSource2"
     type="HSQL"/>  
  3. <bean id="txManager1"class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
  4.     <property name="dataSource" ref="dataSource1"/>  
  5. </bean>  
  6. <bean id="txManager2"class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
  7.     <property name="dataSource"
     ref="dataSource2"/>  
  8. </bean>  

此處使用jdbc:embedded嵌入資料庫來完成測試,資料庫使用HSQL。

2、 方法級別的@Sql

Java程式碼  收藏程式碼
  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. publicclass MethodLevelSqlTest {  
  6.     private JdbcTemplate jdbcTemplate1;  
  7.     private JdbcTemplate jdbcTemplate2;  
  8.     @Autowired
  9.     @Qualifier("dataSource1")  
  10.     publicvoid setDataSource1(DataSource dataSource1) {  
  11.         this.jdbcTemplate1 = new JdbcTemplate(dataSource1);  
  12.     }  
  13.     @Autowired
  14.     @Qualifier("dataSource2")  
  15.     publicvoid setDataSource2(DataSource dataSource2) {  
  16.         this.jdbcTemplate2 = new JdbcTemplate(dataSource2);  
  17.     }  
  18.     @Test
  19.     @Sql(value = {"classpath:schema.sql""classpath:init-data.sql""classpath:updated-data.sql"},  
  20.             config =  
  21.             @SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",  
  22.                     dataSource = "dataSource1", transactionManager = "txManager1"))  
  23.     publicvoid test01_simple() {  
  24.         Assert.assertEquals(  
  25.                 Integer.valueOf(3),  
  26.                 jdbcTemplate1.queryForObject("select count(1) from users", Integer.class));  
  27.     }  
  28.     @Test
  29.     @Sql(value = {"classpath:schema.sql""classpath:init-data.sql"},  
  30.             config =  
  31.             @SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",  
  32.                     dataSource = "dataSource2", transactionManager = "txManager2"))  
  33.     publicvoid test02_simple() {  
  34.         Assert.assertEquals(  
  35.                 Integer.valueOf(2),  
  36.                 jdbcTemplate2.queryForObject("select count(1) from users", Integer.class));  
  37.     }  
  38. }  

方法級別的@Sql在每個方法上都會執行。其中@Sql可以指定多個sql檔案,然後通過@SqlConfig指定其編碼、分隔符、註釋字首、使用哪個資料來源和事務管理器。

3、類級別的@Sql

Java程式碼  收藏程式碼
  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. publicclass ClassLevelSqlTest {  
  10.     private JdbcTemplate jdbcTemplate1;  
  11.     @Autowired
  12.     @Qualifier("dataSource1")  
  13.     publicvoid setDataSource1(DataSource dataSource1) {  
  14.         this.jdbcTemplate1 = new JdbcTemplate(dataSource1);  
  15.     }  
  16.     @Test
  17.     publicvoid test01_simple() {  
  18.         Assert.assertEquals(  
  19.                 Integer.valueOf(3),  
  20.                 jdbcTemplate1.queryForObject("select count(1) from users", Integer.class));  
  21.     }  
  22. }  

類級別的對整個測試用例中的每個方法都起作用。 

4、指定多個@Sql 

Java8之前需要使用@SqlGroup,而Java8之後直接使用多個@Sql註解即可。

Java程式碼  收藏程式碼
  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. @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)  
  18. publicclass ClassLevelSqlGroupTest {  
  19.     private JdbcTemplate jdbcTemplate1;  
  20.     private JdbcTemplate jdbcTemplate2;  
  21.     @Autowired
  22.     @Qualifier("dataSource1")  
  23.     publicvoid setDataSource1(DataSource dataSource1) {  
  24.         this.jdbcTemplate1 = new JdbcTemplate(dataSource1);  
  25.     }  
  26.     @Autowired
  27.     @Qualifier("dataSource2")  
  28.     publicvoid setDataSource2(DataSource dataSource2) {  
  29.         this.jdbcTemplate2 = new JdbcTemplate(dataSource2);  
  30.     }  
  31.     @Test
  32.     @Transactional()  
  33.     @Sql(value = {"classpath:schema.sql""classpath:init-data.sql""classpath:updated-data.sql"},  
  34.             config =  
  35.             @SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",  
  36.                     dataSource = "dataSource1", transactionManager = "txManager1"))  
  37.     publicvoid test01_simple() {  
  38.         Assert.assertEquals(  
  39.                 Integer.valueOf(3),  
  40.                 jdbcTemplate1.queryForObject("select count(1) from users", Integer.class));  
  41.     }  
  42.     @Test
  43.     @Transactional()  
  44.     @Sql(value = {"classpath:schema.sql""classpath:init-data.sql"},  
  45.             config =  
  46.             @SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",  
  47.                     dataSource = "dataSource2", transactionManager = "txManager2"))  
  48.     publicvoid test02_simple() {  
  49.         Assert.assertEquals(  
  50.                 Integer.valueOf(2),  
  51.                 jdbcTemplate2.queryForObject("select count(1) from users", Integer.class));  
  52.     }  
  53. }  

也可以通過元註解把註解合併:

Java程式碼  收藏程式碼
  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程式碼  收藏程式碼
  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. publicclass TransactionalTest {  
  6.     private JdbcTemplate jdbcTemplate1;  
  7.     private JdbcTemplate jdbcTemplate2;  
  8.     @Autowired
  9.     @Qualifier("dataSource1")  
  10.     publicvoid setDataSource1(DataSource dataSource1) {  
  11.         this.jdbcTemplate1 = new JdbcTemplate(dataSource1);  
  12.     }  
  13.     @Autowired
  14.     @Qualifier("dataSource2")  
  15.     publicvoid setDataSource2(DataSource dataSource2) {  
  16.         this.jdbcTemplate2 = new JdbcTemplate(dataSource2);  
  17.     }  
  18.     @Test
  19.     @Transactional("txManager1")  
  20.     @Sql(value = {"classpath:schema.sql""classpath:init-data.sql""classpath:updated-data.sql"},  
  21.             config =  
  22.             @SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",  
  23.                     dataSource = "dataSource1", transactionManager = "txManager1"))  
  24.     publicvoid test01_simple() {  
  25.         //判斷是在事務中執行
  26.         Assert.assertTrue(TransactionSynchronizationManager.isActualTransactionActive());  
  27.         Assert.assertTrue(TestTransaction.isActive());  
  28.         Assert.assertEquals(  
  29.                 Integer.valueOf(3),  
  30.                 jdbcTemplate1.queryForObject("select count(1) from users", Integer.class));  
  31.     }  
  32.     @Test
  33.     @Transactional("txManager2")  
  34.     @Sql(value = {"classpath:schema.sql""classpath:init-data.sql"},  
  35.             config =  
  36.             @SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",  
  37.                     dataSource = "dataSource2", transactionManager = "txManager2"))  
  38.     publicvoid test02_simple() {  
  39.         Assert.assertEquals(  
  40.                 Integer.valueOf(2),  
  41.                 jdbcTemplate2.queryForObject("select count(1) from users", Integer.class));  
  42.     }  
  43.     @Test
  44.     @Transactional("txManager2")  
  45.     @Sql(value = {"classpath:schema.sql""classpath:init-data.sql"},  
  46.             config =  
  47.             @SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",  
  48.                     dataSource = "dataSource2", transactionManager = "txManager2"))  
  49.     publicvoid test03_simple() {  
  50.         Assert.assertEquals(  
  51.                 Integer.valueOf(2),  
  52.                 jdbcTemplate2.queryForObject("select count(1) from users", Integer.class));  
  53.         TestTransaction.flagForRollback();  
  54.     }  
  55.     @Rule
  56.     public TestName testName = new TestName();  
  57.     @AfterTransaction
  58.     publicvoid afterTransaction() {  
  59.         System.out.println(testName.getMethodName());  
  60.         if("test03_simple".equals(testName.getMethodName())) {  
  61.             Assert.assertEquals(  
  62.                     Integer.valueOf(0),  
  63.                     jdbcTemplate2.queryForObject("select count(1) from users", Integer.class));  
  64.         }  
  65.     }  
  66. }  

可以使用//判斷是在事務中執行TransactionSynchronizationManager.isActualTransactionActive()或TestTransaction.isActive()來判斷是否是在事務中執行;通過TestTransaction.flagForRollback();來回滾事務;在測試用例中@AfterTransaction來斷言回滾後資料沒有插入。

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