Spring FrameworkのUnitテスト実装方法 1-6.Repositoryテスト(Junit4, spring-test, DBUnit, spring-test-dbunit) ※csvファイルからセットアップする

Spring FrameworkのUnitテスト実装方法 1-6.Repositoryテスト(Junit4, spring-test, DBUnit, spring-test-dbunit) ※csvファイルからセットアップする

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

1-6.Repositoryテスト Junit4, spring-test, DBUnit, spring-test-dbunitライブラリを使用したパターン ※csvファイルからセットアップする

1-4をちょっと修正して、xmlファイルからセットアップする設定をcsvファイルからセットアップする設定に書き換えるパターンです。
※xlsxファイルでセットアップするパターンはこちら

【pom.xml】

1-4の実装時と同じです。

<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);
}

【テストクラス】

TodoRepositoryTestVerSpringTestDBunitCsv.java

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:META-INF/spring/test-context-dbunit.xml"})
//@TestExecutionListeners・・・TestContextManagerに指定したListenerを設定する。
//正直あまり良くわかってない。spring-test-dbunitを使う時はお決まり的なやつらしい。
//TransactionDbUnitTestExecutionListenerがspring-test-dbunitで必要だからかも。
@TestExecutionListeners({
    DependencyInjectionTestExecutionListener.class,
    DirtiesContextTestExecutionListener.class,
    TransactionDbUnitTestExecutionListener.class,
    SqlScriptsTestExecutionListener.class
})
//@DbUnitConfiguration・・・自作したDataSetLoaderを使う時にこのアノテーションで設定する。
//csvファイルを読み込ませるようにしたDataSetLoaderを自作したため設定。
@DbUnitConfiguration(dataSetLoader = CsvDataSetLoader.class)
@Transactional
public class TodoRepositoryTestVerSpringTestDBunitCsv {
    
    @Inject
    TodoRepository target;
    
    @Inject
    JdbcTemplate jdbctemplate;
    
    @Before
    public void setUp() {
        //spring-test-dbunitアノテーションでセットアップと比較を行うため、処理なし
    }
    
    @Test
    //@DatabaseSetup・・・spring-test-dbuniライブラリのアノテーション。テスト実行前にデータをセットアップしてくれる。テストクラスごと、メソッドごとでの指定が可能
    //注意:指定するパスは「ディレクトリ」であること。そのディレクトリの「table-ordering.txt」を読みにいき、そこに記述してあるcsvファイルを読みにいく
    @DatabaseSetup("classpath:META-INF/dbunit/actCsv/")
    //@ExpectedDatabase・・・spring-test-dbuniライブラリのアノテーション。テストメソッド実行後のテーブルの状態を指定したファイルと比較検証してくれる。
    //エラーの時はJunitの例のバーが赤くなる。
    //注意:指定するパスは「ディレクトリ」であること。そのディレクトリの「table-ordering.txt」を読みにいき、そこに記述してあるcsvファイルを読みにいく
    @ExpectedDatabase(value="classpath:META-INF/dbunit/expCsv/", assertionMode = DatabaseAssertionMode.NON_STRICT)
    public void testUpdate() {
        //テスト用のデータを作成(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);
    }
}

コメントにも書いていますが、csvファイルのセットの時には気を付ける点があります。

まずcsvファイルでセットアップする流れを説明するとこうなります。
1.テストクラスの@DatabaseSetupアノテーションで、「table-ordering.txt」が存在するディレクトリを読み込む
2.「table-ordering.txt」の中に記述されているcsvファイル名をもとにしてcsvファイルを読み込む

ということで、csvファイルをアノテーションから直接指定して読み込ませるのではなく、「table-ordering.txt」というファイルを介して読み込ませる感じになってます。
よって、@DatabaseSetupや@ExpectedDatabaseで指定するパスはディレクトリになります。

自分の場合は、セットアップ用に読み込ませるtable-ordering.txtとテスト後の検証用に読み込ませるtable-ordering.txtを別にするために、ディレクトリ構造を別にしました。

CsvDataSetLoader.java

//AbstractDataSetLoaderクラスを継承する
public class CsvDataSetLoader extends AbstractDataSetLoader {

    //標準のxml形式からcsv形式のフォーマットを読み込む設定に変更(override)する
    @Override
    protected IDataSet createDataSet(Resource resource) throws Exception {
        // TODO 自動生成されたメソッド・スタブ
        return new CsvURLDataSet(resource.getURL());
    }
}

AbstractDataSetLoaderクラスを継承させて、csvファイルを読み込ませるようにoverrideしています。
CsvURLDataSetメソッドはディレクトリパスを引数に取ります。

【その他設定】

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>

actCsvディレクトリ配下 ※セットアップ用データ
todo.csv

TODO_ID,TODO_TITLE,FINISHED,CREATED_AT
"cceae402-c5b1-440f-bae2-7bee19dc17fb","one",false,"2017-10-01 15:39:17.888"
"5dd4ba78-ff5b-423b-aa2a-a07118aeaf90","two",false,"2017-10-01 15:39:19.981"
"e3bdb9af-3dde-40b7-b5fb-4b388567ab45","three",false,"2017-10-01 15:39:28.437"

ファイル名がテーブル名
1行目がカラム名
2行目以降がカラムに対してのデータ
になってます。

table-ordering.txt

todo

中身はこれだけですw
注意はファイル名だけで拡張子は付けないこと。
もし複数テーブルにデータをセットアップしたいのであれば、この中にファイル名を追記していく形になります。
外部参照制約とか、整合性エラーとか考えるならデータをセットアップする順番に注意しましょう。

expCsvディレクトリ配下 ※テストメソッド実行後の検証用データ
todo.csv

TODO_ID,TODO_TITLE,FINISHED,CREATED_AT
"5dd4ba78-ff5b-423b-aa2a-a07118aeaf90","two",false,"2017-10-01 15:39:19.981"
"cceae402-c5b1-440f-bae2-7bee19dc17fb","one",true,"2017-10-01 15:39:17.888"
"e3bdb9af-3dde-40b7-b5fb-4b388567ab45","three",false,"2017-10-01 15:39:28.437"

テストメソッドの内容が、ID”cceae402-c5b1-440f-bae2-7bee19dc17fb”のデータに対してFinishedをtrueにする内容なので、
ID=”cceae402-c5b1-440f-bae2-7bee19dc17fb”のFINISHEDを”true”に変更しています。

table-ordering.txt

todo

中身はactCsvディレクトリ配下と同じ

xlsxファイルの設定の時は、何も考えずにアノテーションにファイル名を指定すればよかったのに対して、
csvファイルの場合はちょっと面倒な感じがします。あとテーブルやデータ数が多くなってきた時にテーブルの数だけcsvファイルが増えていくことになるので管理が大変になりそうです。

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

DBunitカテゴリの最新記事