過去のエントリで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のテーブルにしたものです。