私にとって、この種のテストはコードの臭いです。問題は常にです:このテストは正確に何をテストしますか?このテストでは、何を信頼し、何を信頼しませんか?
私にとって、read()とwrite()を一緒に信頼することはできません。これらはおそらく同じクラスにあり、同じ人によって書かれています。したがって、write()を呼び出してread()をテストしている場合、これは適切なテストではありません。write()とread()が同期していることをテストしているのであって、本来の動作をしているわけではありません。
2番目の例では、copyとequalsが同期していることをテストしていますが、同じ問題です。
これが永続層の実装だったとしましょう。
public class PersistenceLayer {
private Object object;
void write(Object object) {
this.object = object;
}
Object read(Long id) {
return object;
}
}
問題は、この永続層でテストに合格するかどうかです。しかし、それは明らかにあなたが望むことをしません。データベースには近づきません。同様に、読み取りと書き込みでセッション/トランザクションを共有した場合、テストは合格しますか?この場合、データが実際にデータベースにコミットされることはありません。最後にロールバックを行う場合があります。しかし、あなたのテストはまだ合格します。
説明を読んで、write()を呼び出してからread()を呼び出すと、同様のオブジェクトが返されることをテストしています。write()メソッドに期待するのは、データベースにデータを書き込むことです。したがって、それをテストしている場合は、それを確認する必要があります。したがって、読み取りと書き込みをテストするために使用できる別のチャネルが必要です。これは通常、JDBCを介して新しい接続を作成し、選択を実行することになります。
だから私のテストコードは
testWrite() {
write(o);
Object o2 = readByJdbc("SELECT * FROM table WHERE id = ?", o);
assertObjectsEqual(o, o2); // this needs to compare all values
}
testRead() {
write(o);
Object o2 = read(o.id);
Object o3 = readByJdbc("SELECT * FROM table WHERE id = ?", o);
assertObjectsEqual(o2, o3); // this needs to compare all values
}
testWrite()はデータベースに書き込み、JDBC接続を開いてその方法で読み取ることにより、データがデータベースに書き込まれるようにします(異なるセッション、異なるトランザクション、つまりデータはデータベースにあります)。
testRead()はデータベースに書き込み、永続層とjdbcを介した読み取りによって返された2つのオブジェクトを比較します。write(o)の呼び出しを複製していますが、他のテストが呼び出されたときにwriteが機能するかどうかがわかっているので、許容できます。別のwriteByJdbcを作成することもできますが、2つではなく1つのテストが失敗するだけです。
実際、パラノイアのレベルによっては、assertObjectsEqual()のすべての値を比較する必要はありません。たとえば、Hibernateを使用している場合は、すべてが正しく宣言されていると想定し、データベースに行が存在するかどうかをテストできます。私は休止状態を信頼しているので、これを頻繁に行います。ただし、その場合は、Hibernateの呼び出し方法、オブジェクトの定義方法をテストする必要があります。
jdbcコードは長くて複雑である必要はありません。単純な選択のために、列から値へのマップのリストを作成するだけです。
private List<Map<String, Object>> resultSetToListMap(ResultSet resultSet) throws SQLException {
int columnCount = resultSet.getMetaData().getColumnCount();
List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
while (resultSet.next()) {
Map<String, Object> map = new LinkedHashMap<String, Object>();
for (int i = 1; i <= columnCount; i++) {
map.put(resultSet.getMetaData().getColumnName(i), resultSet.getObject(i));
}
list.add(map);
}
return list;
}
これは、ほとんどのテストには十分すぎるほどです。