java - 解决 JUnit 中的重复测试习语

标签 java unit-testing coding-style junit xunit

我有 2 个案例对我来说似乎是同一个问题,尽管它们是完全不同的情况:

1) 我正在测试对象对数据库的读写。因为我每次都在清理和重建对象,写入测试需要读取以确认每个字段的写入,而读取测试是先写入,所以测试最终看起来是一样的。然而,我不想让接口(interface)中的主要方法未经测试。

2) 在更小的情况下,我正在为一个小数据对象测试一个 copy() 方法和一个 equals() 方法。 copy() 方法使用 equals() 来测试自身,而 equals() 方法正在针对副本进行测试。同样,测试是重复的。

我觉得我在这里遗漏了一些东西,一些方法来分离依赖而不创建大量额外的工作(比如让原始 JDBC 写入数据库等)有没有一种标准的方法来处理这种情况重复测试?

最佳答案

对我来说,这种测试是一种代码味道。问题始终是:此测试究竟测试了什么?对于这个测试,您信任什么,不信任什么?

对我来说,你不能同时信任 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;
    }
}

问题是,你的测试会通过这个持久层吗?但它显然不会做你想要的。它不靠近数据库。同样,如果您的读写共享 session /事务,您的测试会通过吗?在这种情况下,数据可能永远不会真正提交给数据库。它可能会在最后进行回滚。但是您的测试仍然会通过。

阅读您的描述,您正在测试当我调用 write() 然后调用 read() 时,我得到一个类似的对象。我对 write() 方法的期望是它将数据写入数据库。所以如果我正在测试那个,我需要检查那个。所以我必须有另一个 channel 可以用来测试读写。这通常以通过 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 连接并以这种方式读取(不同的 session ,不同的事务,即数据将在数据库中)写入数据库。

testRead() 写入数据库并比较通过持久层和通过jdbc 读取返回的两个对象。我正在复制对 write(o) 的调用,但它是可以接受的,因为我们知道当另一个测试被调用时 write 是否会起作用。我可以再写一个 writeByJdbc,但我得到的只是一个测试会失败,而不是两个。

事实上,根据您的偏执程度,您不需要比较 assertObjectsEqual() 中的所有值。例如,如果您使用的是 hibernate,您可以假设所有内容都已正确声明,并测试数据库中是否存在该行。我经常这样做,因为我相信 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;
}

这对于大多数测试来说已经足够了。

关于java - 解决 JUnit 中的重复测试习语,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7988107/

相关文章:

java - 以编程方式设置 ImageView SRC Android

java - 将 HornetQ(2.2.x) 与 Spring 3.1 集成

java - 使用 Jersey Rest 测试框架和 Mockito 进行单元测试

unit-testing - 如何以规范形式编写单元测试?

java - 关于Java重数学计算的问题

.net - 有关测试或单元测试的一些基本问题

java - 是否可以调用模拟对象的方法?

c++ - 如何打开用户输入的文件名?

java - 编码实践,项目文件夹结构

java - Intellij 中构造函数的自动填充 stub 参数