Java
unittest
dbsetup

JavaでのDBのテストデータ作成はDbSetupが楽

More than 1 year has passed since last update.

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ドキュメントを見れば分かるように、とてもシンプルで、実行も速いです。日本では全く知られてないのがもったいないです。検討してみてはどうでしょうか。