Javaでのデータベースのテストデータ作成にはDBUnitがよく使われますが、自分はDbSetupをオススメします。
なぜDBUnitがイマイチなのか
自分も最初はDBUnitを使ってたのですが、以下の理由からしっくり来ませんでした。
DBを使ったテストでは少量のデータを使うことが多い
ホワイトボックステストで大量のデータを使うことはほとんどなく、単一または複数のテーブルに対して、少量のデータを用意するケースがほとんどです。なので、テストごとにファイル(XML or Excel)を用意するのは面倒です。
テストコードとデータが分離している
テストデータを外部ファイルに保存するため、テストコードとテストデータが分離してしまっています。そのため、何をテストしているのかが分かり辛いです。
そこでDbSetup
そこで見つけたのがDbSetupです。DbSetupはテストデータをJavaコードとして書きます。そのため、少量のテストデータが書きやすく、テストコードとテストデータの位置が近いため、何をテストしているのかが分かりやすいです。
DbSetupの使い方
Destinationオブジェクト
まず接続に必要なDestinationオブジェクトですが、これは2通りの方法で書けます。
// 1. javax.sql.DataSourceから構築
Destination dest = new DataSourceDestination(datasource);
// 2. URL, User, Passwordから構築
Destination dest = new DriverManagerDestination(url, user, password);
テストデータの準備
DbSetupのテストデータは、「テスト対象テーブルのクリア」「テストに必要な小さなデータの定義」の2つからなります。
クリアするテーブルの指定
以下のように、テストで使用するテーブルをクリアするための、Operationオブジェクトを作成します。
import static com.ninja_squad.dbsetup.Operations.*;
// deleteAllFromは複数指定も可能(可変長引数)
public static final Operation DELETE_ALL = deleteAllFrom("character");
// truncateを使う場合
public static final Operation TRUNCATE = truncate("character");
// 一部分だけ削除したいときはSQLを直接書く
public static final Operation DELETE_PARTIAL = sql("delete from character where age < 20");
データの定義
以下のように、テストデータを定義します。まずは、最初に列名を定義してからデータを入れる方法です。
import static com.ninja_squad.dbsetup.Operations.*;
public static final Operation INSERT =
// テーブルの指定
insertInto("character")
// 全てのレコードに同じ値をセットする場合
.withDefaultValue("gender", "女性")
// 列の定義
.columns("headgear", "clothing", "shoes")
// 1つ目のレコード
.values("ヘッドバンド ホワイト", "わかばイカT", "キャンバス ホワイト")
// 2つ目のレコード
.values("フェイスゴーグル", "スクールブレザー", "パワードレッグス")
// Operationオブジェクトを作成
.build();
もう一つは、列と値を同時にセットする方法です。こちらの方が少し冗長ですが、列が多い場合はこちらの方が見やすいので、使い分けてください。Mapから作成する方法もあります。
import static com.ninja_squad.dbsetup.Operations.*;
public static final Operation INSERT =
// テーブルの指定
insertInto("character")
// 全てのレコードに同じ値をセットする場合
.withDefaultValue("gender", "女性")
// 1行目の作成
.row().column("headgear", "ヘッドバンド ホワイト")
.column("clothing", "わかばイカT")
.column("shoes", "キャンバス ホワイト")
.end()
// 2行目の作成
.row().column("headgear", "フェイスゴーグル")
.column("clothing", "スクールブレザー")
.column("shoes", "パワードレッグス")
.end()
// Operationオブジェクトの作成
.build();
Operationをつなげる
バラバラに作成したOperationオブジェクトを実行したい順番に繋げて、1つのOperationオブジェクトにします。Operationはバラバラに作成できて、かつオブジェクトを生成した段階では何も行われないため、複数のクラス間で共有することも容易です。
import static com.ninja_squad.dbsetup.Operations.*;
Operation ops = sequenceOf(DELETE_ALL, INSERT);
そして実行
最後に、DbSetupクラスにDestinationとOperationを渡すことで、実行されます。
DbSetup dbSetup = new DbSetup(dest, ops);
dbSetup.launch();
最後に
DbSetupは他にもいろいろ機能がありますが、APIドキュメントを見れば分かるように、とてもシンプルで、実行も速いです。日本では全く知られてないのがもったいないです。検討してみてはどうでしょうか。