Wiki

Clone wiki

20110515-tddbc-forum / Database / DbUnitTestCase

テストケースの作成

データベースに接続するユニットテストを作成します。

概要

データベースに接続するユニットテストは、次の手順で実行する必要があります。

  1. データベースの各テーブルを初期化する
  2. データベースにアクセスするプログラムを実行する
  3. データベースの内容と期待する結果が一致するかを検証する
  4. データベースの各テーブルを初期状態に戻す ただし、「最後のデータベースの各テーブルを初期状態に戻す」は、初期化時にデータをクリアすれば良いため、基本的には行われません。

このテストの流れで面倒な部分は、データベースの初期化とデータベースの内容との検証の2点です。この面倒は、DbUnitを使う事で簡単に行う事ができます。

データセット

DbUnitではテーブルのレコードをDataSetと呼ばれるオブジェクトで管理します。 DataSetは幾つかの方法で定義できますが、よく使われるのはXML形式とExcel形式です。 どちらも複数のテーブルに複数のレコードを定義する事ができ、DbUnitに含まれる実装クラスを通して使う事ができます。

YamlDataSet

しかし、XML形式もExcel形式も「ちょっと使ってみる」には面倒なフォーマットです。JSONやYAMLで簡単に書ければ楽なので、YAMLを採用し、次のようにデータセットを定義しましょう。

- topic:
  - id: 1
    subject: "TDD Boot Campについて"
    created_by: "shuji_w6e"
    created_at: 2010-05-15 10:20:35 JST

テーブルのスキーマと比較してみれば、特に説明は不要と思われるほど単純な形式です。

※テーブルの順序を保持するために、トップレベルはシーケンス(配列)にします。

このファイルはテスト用のリソースとして扱う為、/src/test/resourcesの下にtddbc.forumパッケージを作成し、TopicRepositoryTest.yamlといった名前で作成して下さい。

YAMLのファイルを読み込んでデータセットオブジェクトを作成するには、 jp.sunflower.utflavor.dbunit.YamlDataSet クラスを使用します。

InputStream resource = getClass().getResourceAsStream("TopicRepositoryTest.yaml");
IDataSet dataSet = new YamlDataSet(resource);

空のデータセット

DbUnitでは、データセットに含まれるテーブルに関して初期化(全データのクリア)を行う仕様になっています。 したがって、データセットに含まれないテーブルは初期化されないので注意して下さい。 空のデータセットを作成するには次のようにEmpty.yamlを作成します。

- topic: []
- message: []

DatabaseTestCase

データベースを利用したテストケースではDbUnitの機能を利用します。

DbUnitの機能を簡単に利用できるようにした基底クラス jp.sunflower.utflavor.dbunit.DatabaseTestCase を使う事で、テストがやりやすくなります。DatabaseTestCaseで、setUp/tearDownをオーバーライドする場合、かならずスーパークラスのメソッドを呼び出すことを忘れないようにしてください。

HibernateのsetUp/tearDownを考慮すると、データベースを使ったテストの基本形は次のようになります。

public MessageRepositoryTest extends DatabaseTestCase {

    @Override
    @Before
    public void setUp() throws Exception {
        super.setUp();
        HibernateUtil.getSession().beginTransaction();
    }

    @Override
    @After
    public void tearDown() throws Exception {
        HibernateUtil.closeSession();
        super.tearDown();
    }

}

フィクスチャをセットアップする

データベースを利用したテストケースではDbUnitの機能を使い、データベースの状態を一定の初期状態にしてから、テストを実行します。

データベースに投入するデータはフィクスチャと呼ばれ、YamlDataSetとしてロードします。ロードしたフィクスチャはDatabaseTesterのsetUpFixturesメソッドを使ってデータベースに投入します。

@Test
public void testname() throws Exception {
    // setup fixture
    IDataSet dataSet = new YamlDataSet(getClass().getResourceAsStream("testname.yaml"));
    super.tester.setUpFixtures(dataSet);
    // exercise
}

Assertion

データベースを用いた更新系のユニットテストでの検証は、データベースの状態が期待されている状態であるかの確認となります。DbUnitを使う事で、データベースの状態と期待されるデータセットを比較することが簡単にできます。

期待される状態は、yamlで記述します。この時、比較したくないカラムは入力を省略することで、入力されているカラムのみを比較させる事ができます。例えば、自動生成されるIDや自動的に現在時刻を設定されるカラムは検証が難しいため、省略する事が必要です。

- topic:
  - subject: "TDD Boot Campについて"
    created_by: "shuji_w6e"

このように期待される結果のサブセットを記述します。

実データの取得

現在のデータベースの状態を取得するには、testerにヘルパメソッドがあるためこれを利用します。

    ITable actual = tester.getTable("TABLE_NAME");

assertTable

検証はテーブル毎に、assertTableメソッドを使用して実施することが出来ます。 assertTableの引数はITable型なので、IDataSetオブジェクトからgetTableメソッドで取得してください。

@Test
public void testname() throws Exception {
    // setup fixture
    IDataSet expectedDataSet = new YamlDataSet(getClass().getResourceAsStream("testname_expected.yaml"));
    ITable expected = expectedDataSet.getTable("TABLE_NAME");
    // exercise
    // verify
    ITable actual = tester.getTable("TABLE_NAME");
    assertTable(actual, expected);
}

まとめ

最後に全体のコードを示します。

@Test
public MessageRepositoryTest extends DatabaseTestCase {
    @Override
    @Before
    public void setUp() throws Exception {
        super.setUp();
        HibernateUtil.getSession().beginTransaction();
    }

    @Override
    @After
    public void tearDown() throws Exception {
        HibernateUtil.closeSession();
        super.tearDown();
    }

    @Test
    public void testname() throws Exception {
        // setup fixture
        IDataSet dataSet = new YamlDataSet(getClass().getResourceAsStream("testname.yaml"));
        super.tester.setUpFixtures(dataSet);
        IDataSet expectedDataSet = new YamlDataSet(getClass().getResourceAsStream("testname_expected.yaml"));
        ITable expected = expectedDataSet.getTable("TABLE_NAME");
        // exercise
        ...
        // verify
        ITable actual = tester.getTable("TABLE_NAME");
        assertTable(actual, expected);
    }
}

Next

Next...

Updated