Spring Test Dbunit,H2數據庫
概述
Dbunit是一個基於JUnit的數據庫集成測試框架。DBUnit 的設計理念就是在測試之前,給對象數據庫植入我們需要的準備數據,最後,在測試完畢後,回溯到測試前的狀態;它使數據庫在測試過程之間處於一種已知狀態,如果一個測試用例對數據庫造成了破壞性影響,它可以幫助避免造成後面的測試失敗或者給出錯誤結果。
Spring Test DbUnit提供了Spring Test Framework與DBUnit之間的集成。使用Spring Test DbUnit提供了註解驅動的數據庫集成測試方式。
為了保證測試可模擬測試場景、可重復執行,我們需要一個簡單容易的數據準備工具;一個隔離的幹凈的數據庫環境。一般都是每次執行前都清掉數據庫然後Dbunit(如果測試沒有自己獨立的庫往往影響其他同事工作),測試完回滾到測試前的狀態。所以這篇wiki後面會介紹內存數據庫用於dbunit,這樣就就可以保證每次測試時都可以有個相當幹凈的環境,而且不會影響其他人的開發。
關於Dbunit的使用在網上可以搜索到很多文章,http://yangzb.iteye.com/blog/947292 寫的很詳細,所以這裏不討論DbUnit的使用,而是直接介紹Spring Test Dbunit的是使用。
Spring Test Dbunit配置和使用
1、項目中引入依賴
<dependency> <groupId>com.github.springtestdbunit</groupId> <artifactId>spring-test-dbunit</artifactId> <version>1.2.0</version> </dependency> <dependency> <groupId>org.dbunit</groupId> <artifactId>dbunit</artifactId> <version>2.5.0</version> </dependency>
2、註冊Spring Test Dbunit監聽器
定義一個測試的基類,其他的測試類集成這個基類,在積累上使用@TestExecutionListeners註解註冊Spring Test Dbunit監聽器,Spring Test DbUnit提供的註解就可以被Spring Test處理。
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration({ "classpath*:"classpath:applicationContext.xml" }) @TestExecutionListeners({ DbUnitTestExecutionListener.class, DirtiesContextTestExecutionListener.class, DependencyInjectionTestExecutionListener.class}) @DbUnitConfiguration(databaseConnection = "h2DataSource") public class SpringTransactionalTestCase { @Test public void testToString() throws Exception { } }
3、數據源配置
如果在Spring Test DbUnit中不配置其他的數據源默認使用Spring容器中id="dataSource"的數據源,Spring Test DbUnit支持配置多數據源。
- 如果需要指定數據源,配置如下:
@DbUnitConfiguration(databaseConnection="h2DataSource") //參見上面的SpringTransactionalTestCase類
applicationContext-mybatis-test.xml配置文件如下:
<!--h2數據源--> <bean id="h2DataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="org.h2.Driver" /> <!-- where the db will be placed (created automatically) --> <property name="url" value="jdbc:h2:./db/test" /> <property name="username" value="sa" /> <property name="password" value="" /> </bean> <!--主連接配置--> <bean id="h2SqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="h2DataSource"/> <!-- 配置掃描Domain的包路徑 --> <property name="typeAliasesPackage" value="com.and1.test.domain"/> <!-- 配置掃描Mapper XML的位置 --> <property name="mapperLocations" value="classpath*:com/and1/test/mapper/**/*.xml"/> <!-- 配置mybatis配置文件的位置 --> <property name="configLocation" value="classpath:mybatis-config.xml"/> <!-- 註冊類型轉換器 --> <property name="typeHandlers"> <list> <ref bean="dateIntTypeHandler"></ref> </list> </property> </bean> <!-- 配置掃描Mapper接口的包路徑 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="sqlSessionFactoryBeanName" value="h2SqlSessionFactory" /> <property name="basePackage" value="com.and1.test.dao.mapper"/> </bean> <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate"> <constructor-arg ref="h2SqlSessionFactory"/> </bean>
- 如果需要配置多數據源(spring-test-dbunit 1.2.0之後的版本才可以配置多數據源),則配置如下
@DatabaseSetup
,@DatabaseTearDown
和@ExpectedDatabase如果沒有指定默認使用第一個第一個數據源(dataSource數據源),如需指定數據源,則如下:
@DatabaseSetup(connection = "dataSource", value = "classpath:com/and1/test/service/deal/DealServiceTest.testSyncDB.setUp.xml")
4、Setup 和 TearDown
@DatabaseSetup
註解用來測試之前配置數據庫的初始狀態, 這個註解可以放在整個測試類上或者單個測試方法上,如果放在類上,則對所有方法都有效。如果不需要準備初始數據,可以不用此註解。
@DatabaseSetup(value = "classpath:com/and1/test/dao/mapper/deal/DealMqMessageMapperTest.setUp.xml", connection = "h2DataSource", type = DatabaseOperation.CLEAN_INSERT)
value:數據集文件,測試執行之前設置數據庫初始狀態的數據集(DataSet)文件,是標準的DbUnit XML文件 (可以利用sequel pro的bundles實現生成xml文件:https://github.com/alsbury/SequelProCopyPHPUnitDataset)
connection:指定數據源,必須是@DbUnitConfiguration中配置的數據源,如果不指定,默認是@DbUnitConfiguration配置的第一個數據源。Spring-test-dbunit 1.2.0之後才支持。
type:對數據庫的操作類型,如果不設置默認是DatabaseOperation.CLEAN_INSERT。
public enum DatabaseOperation { //將數據集中的內容更新到數據庫中。它假設數據庫中已經有對應的記錄,否則將失敗。 UPDATE, //將數據集中的內容插入到數據庫中。它假設數據庫中沒有對應的記錄,否則將失敗。 INSERT, //將數據集中的內容刷新到數據庫中。如果數據庫有對應的記錄,則更新,沒有則插入。 REFRESH, //刪除數據庫中與數據集對應的記錄。 DELETE, //刪除表中所有的記錄,如果沒有對應的表,則不受影響。 DELETE_ALL, //與DELETE_ALL類似,更輕量級,不能rollback。 TRUNCATE_TABLE, //是一個組合操作,是DELETE_ALL和INSERT的組合 CLEAN_INSERT; }
DealMqMessageMapperTest.setUp.xml
<?xml version="1.0" encoding="UTF-8"?> <dataset> <deal_mq_message id="1" deal_id="4234" created_time="2014-10-17 14:37:41"/> </dataset>
DealMqMessageMapperTest.expected.xml
<?xml version="1.0" encoding="UTF-8"?> <dataset> <deal_mq_message id="1" deal_id="4234" /> <deal_mq_message id="2" deal_id="123456" /> </dataset>
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration({ "classpath*:"classpath:applicationContext.xml" }) @TestExecutionListeners({ DbUnitTestExecutionListener.class, DirtiesContextTestExecutionListener.class, DependencyInjectionTestExecutionListener.class}) @DbUnitConfiguration(databaseConnection = "h2DataSource") public class SpringTransactionalTestCase {
<span style="font-family: Arial, Helvetica, sans-serif;">}</span>
@DatabaseTearDown註解
用來指定測試之後期望的數據庫狀態。可以加在方法上或者類上。這個註解非必須,默認是回滾@DatabaseSetup 和test method對數據的更改。
value:數據集文件,測試之後根據這個數據集(DataSet)文件設置數據庫的期望狀態,是標準的DbUnit XML文件。
connection:指定數據源,必須是@DbUnitConfiguration中配置的數據源,如果不指定,默認是@DbUnitConfiguration配置的第一個數據源。Spring-test-dbunit 1.2.0之後才支持。
type:對數據庫的操作類型,如果不設置默認是DatabaseOperation.CLEAN_INSERT。比如我這裏設置的是DatabaseOperation.DELETE,這個操作會刪除DealMqMessageMapperTest.expected.xml裏面的記錄。
5、Expected results
@ExpectedDatabase(value = "classpath:com/and1/test/dao/mapper/deal/DealMqMessageMapperTest.expected.xml", assertionMode = DatabaseAssertionMode.NON_STRICT)
value:期望數據集的文件,測試之後用來和實際數據集進行斷言驗證。
connection:指定數據源,必須是@DbUnitConfiguration中配置的數據源,如果不指定,默認是@DbUnitConfiguration配置的第一個數據源。Spring-test-dbunit 1.2.0之後才支持。
assertionMode:測試結果和DataSet數據文件斷言的類型。DatabaseAssertionMode.DEFAULT作為一個標準的DbUnit測試運行,執行一個完整的期望數據集和實際數據集的比對。DatabaseAssertionMode.NON_STRICT將忽略沒有在期望數據集中出現,但是在實際數據集中出現的 表和列名。當集成測試執行在實際數據庫包含很多有很多列的表中, 這將十分有用。我們不需要定義所有的這些,只需要我們感興趣的表和列。
table:指定table去進行斷言。
query:指定sql查詢語句,檢索實際數據集。必須要指定table,才能使用query。
Spring Test DbUnit的執行過程如下:
@DatabaseSetup -> Test Method執行 -> @ExpectedDatabase -> @DatabaseTearDown
6、事務配置
Spring Test框架本身提供的TransactionalTestExecutionListener和@Transactional增強後事務邊界範圍僅限於在測試方法Test Method內。Spring Teset DbUnit提供了 TransactionDbUnitTestExecutionListener會將事務邊界擴大到Spring Test DbUnit執行的整個過程,事務在@DatabaseSetup註解開始,在@DatabaseTearDown和@ExpectedDatabase執行後結束。
@RunWith (SpringJUnit4ClassRunner. class )
@ContextConfiguration
@Transactional
@TestExecutionListeners ({ DependencyInjectionTestExecutionListener. class ,
DirtiesContextTestExecutionListener. class ,
TransactionDbUnitTestExecutionListener. class })
|
註意:這裏不需要註冊DbUnitTestExecutionListener.class,TransactionDbUnitTestExecutionListener 是對DbUnitTestExecutionListener 進行了事務增強,如果兩者都配置的話@DatabaseSetup,@ExpectedDatabase,@DatabaseTearDown會執行兩次。
H2數據庫
1、依賴
<dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <version>1.4.184</version> </dependency> <!-- maven sql 插件 --> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>sql-maven-plugin</artifactId> <version>1.5</version> <dependencies> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <version>1.4.184</version> </dependency> </dependencies> <configuration> <driver>org.h2.Driver</driver> <url>jdbc:h2:./db/mtdc</url> <username>sa</username> <password></password> <skip>${maven.test.skip}</skip> <!--<srcFiles>--> <!--<srcFile>src/test/resources/dc.sql</srcFile>--> <!--</srcFiles>--> </configuration> <executions> <execution> <id>drop-table</id> <phase>process-test-resources</phase> <goals> <goal>execute</goal> </goals> <configuration> <url>jdbc:h2:./db/mtdc</url> <autocommit>true</autocommit> <srcFiles> <srcFile>src/test/resources/dc_drop_table.sql</srcFile> </srcFiles> <onError>continue</onError> </configuration> </execution> <execution> <id>create-table</id> <phase>process-test-resources</phase> <goals> <goal>execute</goal> </goals> <configuration> <url>jdbc:h2:./db/mtdc</url> <autocommit>true</autocommit> <srcFiles> <!--<srcFile>src/test/resources/dc_drop_table.sql</srcFile>--> <srcFile>src/test/resources/dc.sql</srcFile> </srcFiles> </configuration> </execution> </executions>
2、h2測試庫的建表語句
src/test/resources/dc_drop_table.sql),另一個是建表的sql(src/test/resources/dc.sql)。
不支持表級別comment字段不支持 COLLATE utf8_bin 字段不支持CHARACTER SET utf8mb4 字段不支持CHARACTER SET utf8
3、sql-maven-plugin 插件
它通過Maven來執行配置好的數據庫腳本,可以通過在POM中配置sql命令,或者將腳本寫在文件中,在POM中配置文件位置。最後,運行 mvn sql:execute 以執行所有腳本。具體的配置參考上面的依賴。腳本插件包括以下步驟:
- 刪除h2 中mtdc庫中的所有表
- 創建表,索引等
當然我們可以根據具體情況裁剪這些步驟,比如,如果我們需要在一段時間內使用這個腳本創建的幹凈數據庫環境,需要註意的是,執行很多DDL的時候我們一般需要最高的數據庫權限。
4、數據源配置
參考spring test dbunit的數據源的配置。總結
通過建一個Maven項目,使用 maven-sql-plugin 管理數據庫腳本的執行,通過Spring test dbunit去實現數據庫初始數據準備與還原,然後使用CI服務器來調用這個Maven項目,我們就可以實現基於Maven的實現數據庫的持續集成測試了。
Spring Test Dbunit,H2數據庫