Spring FrameworkのUnitテスト実装方法 1-7.Repositoryテスト(Junit4, spring-test, DBSetup)
TERASOLUNA Server Framework for Java (5.x) Development Guideline
サンプルソースはこちら
(これのMyBatis3を使用したパターンで作成してます。)
1-7.Repositoryテスト Junit4,Spring-test,DBSetupライブラリを使用したパターン
DBSetupライブラリはその名の通り、テスト時にデータをセットアップするためのライブラリです。
DBUnitを使用した場合と比較すると、メリットは
・Javaファイルでセットアップデータの記述ができるので、xmlファイルが不要になる。
・同じデータの繰り返していわゆるデータを「膨らます」場合、膨らませるデータの個数や設定を制御できるのでxmlファイルに同じデータをコピペしなくて済むから楽。
・セットアップをし直すかどうかの制御ができるので、必要最小限のセットアップで済みその分動作が軽くなる。
などが挙げられるでしょうか・・・?
一方で、デメリットとしては
・セットアップ用のライブラリなので、DBunitでいうところの@ExpectedDatabaseといった検証用の機能は無い(調べたらあるかもですが。)
・DBunitと比べて使っている人が少な目
といったところかも。
【pom.xml】
DBSetupライブラリが必要になります。
<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>com.ninja-squad</groupId>
<artifactId>DbSetup</artifactId>
<version>2.1.0</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);
}
【テストクラス】
TodoRepositoryTestVerDBsetup.java
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:META-INF/spring/test-context.xml"})
@Transactional
public class TodoRepositoryTestVerDBsetup {
@Inject
TodoRepository target;
@Inject
DataSource dataSource;
@Inject
JdbcTemplate jdbctemplate;
private static DbSetupTracker TRACKER = new DbSetupTracker();
@Before
public void setUp() {
//DBSetupを使う準備
Destination dest = new DataSourceDestination(dataSource);
//sequenceOfメソッドで囲むことによって、連続してデータに対しての処理を実行できる。
Operation ops = Operations.sequenceOf(DbsetupOperations.INIT_TABLE,
DbsetupOperations.SETUP_TABLE_A);
DbSetup dbSetup = new DbSetup(dest, ops);
//TRACKERでセットアップを制御する。
TRACKER.launchIfNecessary(dbSetup);
}
@Test
public void testUpdate() throws Exception{
//テスト用のデータを作成(getTodoDataメソッドはDBからデータを取得するprivateメソッド。取得したデータを書き換えて更新する。)
SimpleDateFormat sdFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
String todoId = "cceae402-c5b1-440f-bae2-7bee19dc17fb";
Todo testDataTodo = getTodoData(todoId);
testDataTodo.setFinished(true);
//updateメソッドのテスト
boolean actTodo = target.update(testDataTodo);
//結果検証
assertEquals(actTodo, true);
//期待値の作成
Todo exptodo = new Todo();
exptodo.setTodoId("cceae402-c5b1-440f-bae2-7bee19dc17fb");
exptodo.setTodoTitle("one");
exptodo.setFinished(true);
String strDate = "2017-10-01 15:39:17.888";
Date date = sdFormat.parse(strDate);
exptodo.setCreatedAt(date);
//処理後データの取得(getTodoDataメソッドはDBからテスト後に変更されたデータを取得するprivateメソッド)
Todo actTestDataTodo = getTodoData(todoId);
//メソッド実行後テーブルデータ検証
//date型の表示形式が異なるため、時刻文字列に変換して比較している
assertEquals(exptodo.getTodoId(), actTestDataTodo.getTodoId());
assertEquals(exptodo.getTodoTitle(), actTestDataTodo.getTodoTitle());
assertEquals(exptodo.isFinished(), actTestDataTodo.isFinished());
assertEquals(sdFormat.format(exptodo.getCreatedAt()) ,sdFormat.format(actTestDataTodo.getCreatedAt()));
/*
* TRACKERによるセットアップの制御
* テスト対象が参照系(select)の場合・・・参照のみでありデータベースを更新していないので、データの再セットアップは不要。
* テスト対象が更新系(insert, update, delete)の場合・・・更新されたデータベースのままだと次のテストに影響を与えるので、データのセットアップをし直す必要がある。
* TRACKER.skipNextLaunchメソッドを実行することで、次のテスト(@Test)の前に実行される@Beforeのデータセットアップ処理をスキップすることができる。
*
* 今回はupdateメソッドがテスト対象のため、TRACKER.skipNextLaunch();をコメントアウトしている。
*/
//TRACKER.skipNextLaunch();
}
}
コメントにも書いてありますが、DBSetupのポイントとしてはセットアップの制御をTRACKERで行っている点です。
DBSetupを使う上で必須というわけではないのですが、この制御によって不必要なセットアップを減らすことができます。
更新系の処理の時にのみデータの再セットアップを行って綺麗な状態で始める・・・といったことが可能です。
DbsetupOperations.java
public class DbsetupOperations {
/*
* テーブルデータを初期化するメソッド
*/
public static final Operation INIT_TABLE =
Operations.sequenceOf(
Operations.deleteAllFrom("todo"));
/*
* テーブルにデータをセットアップするメソッド(パターンA)
*/
public static final Operation SETUP_TABLE_A =
Operations.sequenceOf(
Operations.insertInto("todo")
.columns("todo_id","todo_title","finished","created_at")
.values("cceae402-c5b1-440f-bae2-7bee19dc17fb","one",false,"2017-10-01 15:39:17.888")
.values("5dd4ba78-ff5b-423b-aa2a-a07118aeaf90","two",false,"2017-10-01 15:39:19.981")
.values("e3bdb9af-3dde-40b7-b5fb-4b388567ab45","three",false,"2017-10-01 15:39:28.437")
.build()
);
/*
* テーブルにデータをセットアップするメソッド(パターンB)
* パターンAとの違いは1行ずつカラムに対してデータを指定している点。
*/
public static final Operation SETUP_TABLE_B =
Operations.sequenceOf(
Operations.insertInto("todo")
//row0
.row()
.column("todo_id", "cceae402-c5b1-440f-bae2-7bee19dc17fb")
.column("todo_title", "one")
.column("finished", false)
.column("created_at", "2017-10-01 15:39:17.888")
.end()
//row1
.row()
.column("todo_id", "5dd4ba78-ff5b-423b-aa2a-a07118aeaf90")
.column("todo_title", "two")
.column("finished", false)
.column("created_at", "2017-10-01 15:39:19.981")
.end()
//row2
.row()
.column("todo_id", "e3bdb9af-3dde-40b7-b5fb-4b388567ab45")
.column("todo_title", "three")
.column("finished", false)
.column("created_at", "2017-10-01 15:39:28.437")
.end()
.build()
);
}
データセットアップ用のクラスです。
これ以外にデータの膨らまし用に使える処理とかもあります。
詳しくはDBSetupの本家HPに。。。
【その他設定】
test-context.xml
JdbcTemplateを使えるように設定します。(データ検証用のため)
基本はapplicationContext.xmlの設定を丸パクリして、不必要なものを削った感じです。
<!-- jdbcTemplateの設定 -->
<bean class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="dataSource" />
</bean>
xmlとかもう見るだけで虫唾が走って無理だわ!!という方にはおすすめかもしれませんw
何より「流れるようなインタフェース」で作成するというコンセプトがカッコいいし便利だし楽です。
サンプルソースはgithubで公開してます。
Spring Unit Test pattern7


コメントを書く