読者です 読者をやめる 読者になる 読者になる

Fight the Future

何かを始めたら、半分成功したのと同じ

DbUnitライブラリ@TableAssertでDBとアサートできます

DbUnitNG プロジェクト日本語トップページ - SourceForge.JPで期待値のファイルとデータベースのテーブルをアサートするアノテーションを作りました。
@TableAssertです。


こんな感じ。

	@TableAssert(names = "dept", pathname = "insert_expected.xml")
	@SetUpOperation(pathname = "dept.xml", value = DatabaseOperationType.DELETE_ALL)
	public void testTableAssert() {
		insert();
	}

必須属性はnamesとpathnameです。
この2つだけなら、namesにデータベースのテーブル名を記述します。
つまり、今回はdeptテーブルと期待値ファイルをアサートします。


アサートは、期待値のファイルにあるカラムだけ比較します。
pathnameには期待値のファイルを記述します。この場合、「insert_expected.xml」が期待値のファイルです。
ファイル名だけであれば、テストクラスと同パッケージに配置します。
内容はDbUnitの形式です。


SQL文を直接記述することもできます。

	@TableAssert(names = "dept", pathname = "org/dbunitng/sample/dao/insert_expected.xml", queries = "select dname, deptno, loc from dept")
	@SetUpOperation(pathname = "dept.xml", value = DatabaseOperationType.DELETE_ALL)
	public void testTableAssert2() {
		insert();
	}

queries属性にはSQL文を記述します。その結果がDbUnitのITableとなります。ITableのテーブル名はnames属性に記述した名前になります。
つまり、この例ではSQL文の結果がITableとなり、テーブル名はdeptとなります。
XMLで表現すると以下のイメージです。

<dataset>
	<DEPT DEPTNO="1" DNAME="test" LOC="Osaka" />
</dataset>

これを実装するのに散々悩んだのですが、結局一番ダサい方法で実装しました。

ダウンキャスト。。。
ITestListener#onStart(ITestContext context)の引数ITestContextを実装クラスTestRunnerクラスにキャストしてます。


で、リスナーのリストにアクセスします。
リストを取得したら、DbUnitNGライブラリのリスナーが先頭に来るようにソートしてます。

		TestRunner runner = (TestRunner) context;
		List<ITestListener> list = runner.getTestListeners();

		Collections.sort(list, new Comparator<ITestListener>() {
			public int compare(ITestListener o1, ITestListener o2) {
				if (o1 instanceof DbUnitNGTestListener) {
					return -1;
				} else if (o2 instanceof DbUnitNGTestListener) {
					return 1;
				}
				return 0;
			}
		});

あーJavaなのにインタフェースの実装クラスを意識してダウンキャストなんて、一番ダサいプログラミングだよね。。。
他にいい方法が思いつかなかった。。。