我有2个案例对我来说似乎是同样的问题,即使它们情况完全不同:
1)我正在测试对数据库的读写。因为我每次都在清理和重建对象,所以写入测试需要读取以确认每个字段的写入,并且读取测试首先写入,因此测试最终看起来相同。然而,我不想在未经测试的界面中留下一个主要方法。
2)在一个小得多的情况下,我正在测试一个小数据对象的copy()方法和equals()方法。 copy()方法使用equals()来测试自身,而equals()方法正在测试副本。同样,测试也是重复的。
我觉得我在这里遗漏了一些东西,某种方式来分离依赖关系而不创建大量的额外工作(比如将原始JDBC写入数据库等等)是否有一种标准的方法来处理这种情况测试重复?
答案 0 :(得分:1)
作为一个肤浅的测试,你正在做的事情很好。毕竟,你想要做的是断言write方法和read方法是互补的,当你编写和读取时,你获得了一个相等的对象(同样适用于copy和equals) 不幸的是,我不认为你可以在没有额外工作的情况下更深入,正如你已经知道的那样。测试应该非常简单,不需要额外的测试,除非你编写第二个写入和读取实现,否则你必须进行手工操作。
答案 1 :(得分:1)
对我来说,这种测试是代码味道。问题始终是:完全这个测试测试是什么?对于这个测试,你信任什么,不信任什么?
对我来说,你不能信任read()和write(),它们可能属于同一个人,由同一个人写的。因此,如果你通过调用write()测试read(),那么这不是一个好的测试,你测试的是write()和read()是同步的,而不是他们做他们应该做的事情。
在第二个示例中,您正在测试该副本和等号同步,同样的问题。
让我们说这是持久层的实现:
public class PersistenceLayer {
private Object object;
void write(Object object) {
this.object = object;
}
Object read(Long id) {
return object;
}
}
问题是,您的测试是否会通过此持久层传递?但它显然不能做你想要的。它不靠近数据库。同样地,如果你的阅读&写共享会话/事务?在这种情况下,数据可能永远不会实际提交到数据库。它可能会在最后进行回滚。但是你的测试仍然会通过。
阅读你的描述,你正在测试当我调用write()然后read()时,我得到一个类似的对象。我对write()方法的期望是它将数据写入数据库。所以,如果我正在测试那个,我需要检查一下。所以我必须有另一个通道,我可以用来测试读取和放大器写。这通常最终会通过JDBC创建一个新的Connection并执行select。
所以我的测试代码是
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比较读取返回的两个对象。我正在复制写入(o)的调用,但它是可以接受的,因为我们知道在调用其他测试时write是否有效。我可以写另一个writeByJdbc,但我得到的只是一个测试会失败而不是两个。
实际上,根据您的偏执程度,您不需要比较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;
}
这对于大多数测试来说已经足够了。