Spring FrameworkのUnitテスト実装方法 1-3.Repositoryテスト(Junit4, spring-test, DBUnit)

Spring FrameworkのUnitテスト実装方法 1-3.Repositoryテスト(Junit4, spring-test, DBUnit)

Spring FrameworkのUnitテスト実装方法 1-3.Repositoryテスト(Junit4, spring-test, DBUnit)

【サンプルソース】
TERASOLUNA Server Framework for Java (5.x) Development Guideline
サンプルソースはこちら
(これのMyBatis3を使用したパターンで作成してます。)

1-3.Repositoryテスト Junit4,Spring-test,DBUnitライブラリを使用したパターン

セットアップを簡単にするために、DBUnitを使ってxmlファイルからデータのセットアップを行います。

【pom.xml】

DBUnitライブラリを使うために追加してます。

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.dbunit</groupId>
        <artifactId>dbunit</artifactId>
        <version>2.5.4</version>
        <scope>test</scope>
   </dependency>
</dependencies>

【テスト対象クラス】

TodoRepository.java
テスト対象はupdateメソッド

public interface TodoRepository {
   Todo findOne(String todoId);

    Collection<Todo> findAll();

    void create(Todo todo);

    boolean update(Todo todo);

    void delete(Todo todo);

    long countByFinished(boolean finished);
}

【テストクラス】

TodoRepositoryTestVerDBunit.java

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:META-INF/spring/test-context-dbunit.xml"})
@Transactional
public class TodoRepositoryTestVerDBunit extends DataSourceBasedDBTestCase {

    private final String RESOURCE_DIR = "src/test/resources/META-INF/dbunit/";
    
    @Inject
    TodoRepository target;
    
    @Inject
    JdbcTemplate jdbctemplate;
    
    @Inject
    private TransactionAwareDataSourceProxy dataSourceTest;
    
    @Before
    public void setUp() throws Exception {
        super.setUp();
        
        /* 意味ないかもしれないけど、ここで実行することでファイルとDBの格納後の整合性確認ができる。
        IDataSet databaseDataSet = getConnection().createDataSet();
        ITable actualTable = databaseDataSet.getTable("todo");
        IDataSet expectedDataSet = new FlatXmlDataSetBuilder().build(new File(RESOURCE_DIR + "test_data.xml"));
        ITable expectedTable = expectedDataSet.getTable("todo");
        Assertion.assertEquals(expectedTable, actualTable);
        */
        
    }
    
    @Test
    @Rollback
    public void testUpdate() throws Exception {
        //テスト用のデータを作成(getTodoDataメソッドはDBからデータを取得するprivateメソッド。取得したデータを書き換えて更新する。)
        String todoId = "cceae402-c5b1-440f-bae2-7bee19dc17fb";
        Todo testDataTodo = getTodoData(todoId);
        testDataTodo.setFinished(true);
        
        //updateメソッドのテスト
        boolean actTodo = target.update(testDataTodo);

        //結果検証
        assertEquals(actTodo, true);
        
        //メソッド実行後テーブルデータ検証
        //ここで指定したxmlファイルには、テスト対象のメソッド実行後に更新されたテーブルの内容の期待値を記述している
        Assertion.assertEquals(getexpectedTable(RESOURCE_DIR + "compare_data.xml"), getactualTable());
        
    }
    
    //テーブルからデータを取得
    private ITable getactualTable() throws Exception {
        
        IDataSet databaseDataSet = getConnection().createDataSet();
        ITable actualTable = databaseDataSet.getTable("todo");
        
        return actualTable;
    }
    
    //期待値となるデータをファイルから取得するメソッド。引数はファイルのパス
    private ITable getexpectedTable(String filepath) throws Exception  {
        
        IDataSet expectedDataSet = new FlatXmlDataSetBuilder().build(new File(filepath));
        ITable expectedTable = expectedDataSet.getTable("todo");
        
        return expectedTable;
    }
    
    //DBunitを使用するためのオーバーライド
    @Override
    protected DataSource getDataSource() {
        // TODO 自動生成されたメソッド・スタブ
        return dataSourceTest;
    }
    
    //DBunitを使用するためのオーバーライド
    @Override
    protected IDataSet getDataSet() throws Exception {
        // TODO 自動生成されたメソッド・スタブ
        return new FlatXmlDataSetBuilder().build(new FileInputStream(RESOURCE_DIR + "test_data.xml"));
    }
}

DBUnitの処理について、xmlファイルを読み込むようにメソッドをオーバーライドしてます。

【その他設定】

test-context-dbunit.xml
DBunitを有効にするために少しtest-context.xml(1-1参照)を書き換えてます。
これをしないとDBunitがうまく動いてくれないらしい・・・

<bean id="log4jDataSource" class="net.sf.log4jdbc.Log4jdbcProxyDataSource">
    <constructor-arg index="0" ref="realDataSource" />
</bean>
    
<bean id="dataSource" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
    <constructor-arg index="0" ref="log4jDataSource" />
</bean>

test_data.xml
セットアップ用のデータです。

<?xml version='1.0' encoding='UTF-8'?>
<dataset>
    <TODO TODO_ID="cceae402-c5b1-440f-bae2-7bee19dc17fb" TODO_TITLE="one" FINISHED="false" CREATED_AT="2017-10-01 15:39:17.888" />
    <TODO TODO_ID="5dd4ba78-ff5b-423b-aa2a-a07118aeaf90" TODO_TITLE="two" FINISHED="false" CREATED_AT="2017-10-01 15:39:19.981" />
    <TODO TODO_ID="e3bdb9af-3dde-40b7-b5fb-4b388567ab45" TODO_TITLE="three" FINISHED="false" CREATED_AT="2017-10-01 15:39:28.437" />
</dataset>

compare_data.xml
テストメソッド実行後の検証用データです。
テストメソッドの内容が、ID”cceae402-c5b1-440f-bae2-7bee19dc17fb”のデータに対してFinishedをtrueにする内容なので、
test_data.xmlの内容からID=”cceae402-c5b1-440f-bae2-7bee19dc17fb”のFINISHEDを”true”に変更しています。

<?xml version='1.0' encoding='UTF-8'?>
<dataset>
    <TODO TODO_ID="5dd4ba78-ff5b-423b-aa2a-a07118aeaf90" TODO_TITLE="two" FINISHED="false" CREATED_AT="2017-10-01 15:39:19.981" />
    <TODO TODO_ID="cceae402-c5b1-440f-bae2-7bee19dc17fb" TODO_TITLE="one" FINISHED="true" CREATED_AT="2017-10-01 15:39:17.888" />
    <TODO TODO_ID="e3bdb9af-3dde-40b7-b5fb-4b388567ab45" TODO_TITLE="three" FINISHED="false" CREATED_AT="2017-10-01 15:39:28.437" />
</dataset>

xmlでどんどんデータを書いていけばいいので、大量データのセットアップとかも含めてやっぱりDBUnitによるセットアップがおすすめですね。
データの検証もやってくれるし。
ちなみにテストメソッド実行後のテーブルデータと、compare_data.xmlの内容が異なっていた場合、
Junit上でエラーになります。(例のバーが赤くなる)
ちょっと面倒なのが、compare_data.xmlの中のデータの順番まで合わせなきゃいけないことです。。。
自分がやった限りでは更新後のテーブルの順番にちゃんと合わせないとエラーになるのですが、
データの整合性だけ見てくれるように設定とかできないのですかね・・・

サンプルソースはgithubで公開してます。
Spring-Unit-Test-pattern3

DBunitカテゴリの最新記事