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ファイルからセットアップする

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の実装時と同じです。

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
<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メソッド

01
02
03
04
05
06
07
08
09
10
11
12
13
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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
@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

01
02
03
04
05
06
07
08
09
10
//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がうまく動いてくれないらしい・・・

1
2
3
4
5
6
7
<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

1
2
3
4
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

1
todo

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

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

1
2
3
4
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

1
todo

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

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

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

DBunitカテゴリの最新記事