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

Fight the Future

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

BeanのリストをDbUnitのDataSetに変換する

TestNG

過去のエントリでBeanのListとDbUnitのDataSetの比較をなんとかしたいと思ったわけだけど。
DbUnitの弱点はBeanのListとDataSetを比較できないこと - Fight the Future じゅくのblog
BeanのListとDbUnitのDataSetを比較する方法を考える - Fight the Future じゅくのblog


実装してみた。
まだネストしたBeanには対応してないけど、よくあるDTOみたいなフラットなBeanのListならDataSetにできる。
使い方は簡単。

DeptDao deptDao = new DeptDao();
List<Dept> actual = deptDao.listAllDept();

BeanListConverter converter = new BeanListConverter(actual);
IDataSet dataSet = converter.convert();

この場合、Deptクラスのリストをデータセットに変換してる。
ちなみにDeptクラスはただのBean。

public class Dept implements Serializable {
	private int deptno;
	private String dname;
	private String location;
	// has getters and setters...
}


こうやってBeanのListをDataSetに変換してしまえば、
DbUnitのAssertion#assertEquals(IDataSet, IDataSet)でアサートできます!

List<Dept> actual = deptDao.listAllDept();
BeanListConverter converter = new BeanListConverter(actual);
IDataSet dataSet = converter.convert();

IDataSet initialDataSet = new FlatXmlDataSet(new File("dept.xml"));
Assertion.assertEquals(initialDataSet, dataSet);

試したい方はこちらから!DbUnitNG プロジェクト日本語トップページ - SourceForge.JP
intやStringといった単純なプロパティのものしか試してないので、
DateやBigDecimalみたいなものもテストしなくては。
今からTestNGでテストケース作っていきます!

実装方法

Seasar2のBeanReaderやBeanDescクラスなどをかなり参考にさせてもらいました。


Beanのプロパティをリフレクションで収集して、
それを元にListの各要素であるBeanから値を取り出してます。
このライブラリでは、Beanが持つ1つ1つのプロパティをBeanPropertyクラスとし、
あるBeanが持つプロパティをすべて保持するクラスとしてBeanMetaDataクラスをつくりました。
つまり、BeanMetaDataがBeanPropertyを集約している感じです。


ちょっと抜粋してみると(コメントも主要なとこだけ抜粋)。

public class BeanProperty {
	/**
	 * @param n プロパティ名
	 * @param t プロパティの型
	 * @param f プロパティのフィールド
	 * @param g プロパティのGetter
	 * @param s プロパティのSetter
	 */
	public BeanProperty(String n, Class<?> t, Field f, Method g, Method s) {...}
	/**
	 * プロパティの値を返す。
	 * @param target プロパティを持つオブジェクト
	 */
	public Object getValue(Object target) {...}
}

public class BeanMetaData {
	/** メタデータを収集するクラスを渡す */
	public BeanMetaData(Class<?> clazz) {...}
	/** プロパティ名を渡す */
	public BeanProperty getProperty(String name) {...}
}

値は、適切なBeanPropertyにBeanのインスタンスを渡せば取得できる。


で、DbUnitのデータセットに含まれるITableの実装クラスとして、BeanListTableクラスを作ってます。
これが、BeanのListをDbUnitのテーブルにしたものです。