Spring4.1新特性——資料庫整合測試
阿新 • • 發佈:2019-01-25
在Spring 4.1之前我們在準備測試資料時可能通過繼承AbstractTransactionalJUnit4SpringContextTests,然後呼叫executeSqlScript()進行測試,其中存在一個主要問題:如果要同時執行多個數據源的初始化就靠不住了,而且使用起來也不是特別便利,Spring4.1提供了@Sql註解來完成這個任務。
1、初始化Spring配置:
Java程式碼- <jdbc:embedded-database id="dataSource1" type="HSQL"/>
- <jdbc:embedded-database id="dataSource2"
- <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"
- </bean>
此處使用jdbc:embedded嵌入資料庫來完成測試,資料庫使用HSQL。
2、 方法級別的@Sql
Java程式碼- @RunWith(SpringJUnit4ClassRunner.class)
- @FixMethodOrder(MethodSorters.NAME_ASCENDING)
- @ContextConfiguration(value = "classpath:spring-datasource.xml")
- @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
- publicclass MethodLevelSqlTest {
- private JdbcTemplate jdbcTemplate1;
- private JdbcTemplate jdbcTemplate2;
- @Autowired
- @Qualifier("dataSource1")
- publicvoid setDataSource1(DataSource dataSource1) {
- this.jdbcTemplate1 = new JdbcTemplate(dataSource1);
- }
- @Autowired
- @Qualifier("dataSource2")
- publicvoid 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"))
- publicvoid 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"))
- publicvoid test02_simple() {
- Assert.assertEquals(
- Integer.valueOf(2),
- jdbcTemplate2.queryForObject("select count(1) from users", Integer.class));
- }
- }
方法級別的@Sql在每個方法上都會執行。其中@Sql可以指定多個sql檔案,然後通過@SqlConfig指定其編碼、分隔符、註釋字首、使用哪個資料來源和事務管理器。
3、類級別的@Sql
Java程式碼- @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)
- publicclass ClassLevelSqlTest {
- private JdbcTemplate jdbcTemplate1;
- @Autowired
- @Qualifier("dataSource1")
- publicvoid setDataSource1(DataSource dataSource1) {
- this.jdbcTemplate1 = new JdbcTemplate(dataSource1);
- }
- @Test
- publicvoid test01_simple() {
- Assert.assertEquals(
- Integer.valueOf(3),
- jdbcTemplate1.queryForObject("select count(1) from users", Integer.class));
- }
- }
類級別的對整個測試用例中的每個方法都起作用。
4、指定多個@Sql
Java8之前需要使用@SqlGroup,而Java8之後直接使用多個@Sql註解即可。
Java程式碼- @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)
- publicclass ClassLevelSqlGroupTest {
- private JdbcTemplate jdbcTemplate1;
- private JdbcTemplate jdbcTemplate2;
- @Autowired
- @Qualifier("dataSource1")
- publicvoid setDataSource1(DataSource dataSource1) {
- this.jdbcTemplate1 = new JdbcTemplate(dataSource1);
- }
- @Autowired
- @Qualifier("dataSource2")
- publicvoid 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"))
- publicvoid 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"))
- publicvoid test02_simple() {
- Assert.assertEquals(
- Integer.valueOf(2),
- jdbcTemplate2.queryForObject("select count(1) from users", Integer.class));
- }
- }
也可以通過元註解把註解合併:
Java程式碼- @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、事務
Java程式碼- @RunWith(SpringJUnit4ClassRunner.class)
- @FixMethodOrder(MethodSorters.NAME_ASCENDING)
- @ContextConfiguration(value = "classpath:spring-datasource.xml")
- @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
- publicclass TransactionalTest {
- private JdbcTemplate jdbcTemplate1;
- private JdbcTemplate jdbcTemplate2;
- @Autowired
- @Qualifier("dataSource1")
- publicvoid setDataSource1(DataSource dataSource1) {
- this.jdbcTemplate1 = new JdbcTemplate(dataSource1);
- }
- @Autowired
- @Qualifier("dataSource2")
- publicvoid 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"))
- publicvoid 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"))
- publicvoid 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"))
- publicvoid 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
- publicvoid 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來斷言回滾後資料沒有插入。
本文轉自http://jinnianshilongnian.iteye.com/blog/2106184