私は普段XP(eXtreme Programming)にて開発を行っています。
XPでの開発はテストファーストが基本ですが、アプリケーションの中心にデータベースがいるため、テスト作成の大部分はテストデータ準備コードの記述に割り当てられていました。
モックオブジェクトではデータベースの正しさについてのテストができませんので、何とかして、あるロジックで処理する直前」のデータが必要となるのです。
テストの要件を満たす準備データの検討に時間がかかるのは仕方ない(それがテストファーストというものでしょ)としても、その考え出したデータの投入ロジック記述に大きく時間がかかってしまっていました。
#特にロジックのデータ永続化にORツールを使用しているため、余計に時間がかかります。
DBTestCaseは、エクセルベースで検討した準備データをDBにインサートし、テスト後にデリートするためのツールです。
具体的には、テーブルとエクセルのシートを対応させ、インサートは左のシートから(シート内は上から)順にインサートをし、デリートは右のシートから(シート内は下から)順にデリートしていくユーティリティです。
インサートとデリートで順序が違うのはFKの影響でデータが消せないことを防ぐためです。自分自身を参照しているテーブルでもインサートができればデリートできるはずです。
準備
http://sourceforge.jp/projects/dbtestcase からdbTestCase-0.1.2-src.zipをダウンロ ードします。
#ソース版にもバイナリが含まれているのでせっかくですからソース版をダウンロードします。
ダウンロードしたファイルを解凍すると、出てきたフォルダの直下に dbTestCase-0.1.2.jar というファイルがあるはずです。
このjarファイルがDBTestCaseのライブラリになります。
また、src/libの中にDBTestCaseが必要とするライブラリが入っていますので、各jarにクラスパスを通してください。
テーブルの指定の仕方
エクセルのシート名をテーブル名と同じにする必要があります。
全てのシートが順にパースされていきますので、不要なシートは削除しておく必要があります。
下記のようなエクセルの場合、TABLE_AとTABLE_Bというテーブルに対して処理が行われます。
データの設定の仕方
テーブルに対応したシートにデータを設定します。
シートの一行目に左から詰めて(順番は関係ありません)カラム名を設定していきます。
二行目からはデータの行になります。
空の行は認められませんが、(一行目を含め)背景色をつけたりコメントを追加したりしても問題ありません。
#またオートフィルタ等POIで正しく読めない機能は使用できません。POIに制限されます。
実際の開発での使用には、「シーケンスを使用せずにデータを設定していくのでテスト環境に関してはシーケンスオブジェクトを1000等から開始し、テストデータは1000未満を設定する」等の取り決めが必要でした。
削除キーの指定の仕方
カラム名をBOLDにするだけです。
エクセルのサンプル画像を見てください。
TABLE_BというシートのA1にCOLUMN_AというBOLD文字列がみえるでしょう。
このBOLD文字列のカラム名に対して設定されているデータを削除キーとしてデータを削除します。
コードの基本
net.yher2.junit.db.DBTestCaseというabstractクラスを継承してテストのベースクラスを作成します。
このクラスは、各データベースや接続テクノロジに対応したjava.sql.Connectionを設定可能なようにabstractクラスになっています。
package net.everes.junk;
import java.sql.Connection;
import java.sql.SQLException;
import net.yher2.junit.db.DBTestCase;
public class DBTestSampleBase extends DBTestCase {
protected Connection getConnection() throws SQLException {
//ここにデータベースのコネクションを返すロジックを記述。
return null;
}
}
次に上記クラスを継承した各テストクラスを作成します。
Classpathのオブジェクトにエクセルへのパスを設定し、prepare/clearに渡すことによってデータのインサート/デリートが行われます。
package net.everes.junk;
import net.yher2.commons.io.Classpath;
/**
* 実際のテストクラス
* @author makoto
*
*/
public class DBTestSampleA extends DBTestSampleBase {
private Classpath testDataAPath = null;
private Classpath testDataBPath = null;
/**
* 各テストに必要なデータを用意します。
*/
protected void setUp() throws Exception {
super.setUp();
//クラスパスの通った場所からのエクセルファイルへのパスを設定します。
testDataAPath = new Classpath("test/data/TestAData.xls");
testDataBPath = new Classpath("test/data/TestBData.xls");
prepare(testDataAPath);
prepare(testDataBPath);
}
protected void tearDown() throws Exception {
super.tearDown();
clear(testDataBPath);
clear(testDataAPath);
}
public void testSampleA() throws Exception {
//テストコードを記述
}
}
特殊な使用例
業務用のデータベース設計には、インサートやアップデートの際にトリガーで別テーブルにもデータをインサートするようなものがあります。
そのような場合には、エクセルを複数に分けることで対処することができます。
インサート用のエクセルと別に、トリガーでインサートされるテーブルのデータを削除するためだけのエクセルを用意し、インサート用のエクセルデータ削除前に利用するのです。
junit以外のテクノロジとDBTestCaseを使用する
net.yher2.junit.db.TestDataManagerを使用します。
TestDataManagerにjava.sql.Connectionを設定し、DBTestCaseと同様にprepare/clearによってデータのインサート/デリートを行うことができます。