1. 程式人生 > >Spring Test Dbunit,H2數據庫

Spring Test Dbunit,H2數據庫

float spring 之前 listener hidden ces seo 直接 auto

概述

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 以執行所有腳本。具體的配置參考上面的依賴。

腳本插件包括以下步驟:

  1. 刪除h2 中mtdc庫中的所有表
  2. 創建表,索引等

當然我們可以根據具體情況裁剪這些步驟,比如,如果我們需要在一段時間內使用這個腳本創建的幹凈數據庫環境,需要註意的是,執行很多DDL的時候我們一般需要最高的數據庫權限。

4、數據源配置

參考spring test dbunit的數據源的配置。

總結

通過建一個Maven項目,使用 maven-sql-plugin 管理數據庫腳本的執行,通過Spring test dbunit去實現數據庫初始數據準備與還原,然後使用CI服務器來調用這個Maven項目,我們就可以實現基於Maven的實現數據庫的持續集成測試了。

Spring Test Dbunit,H2數據庫