Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/arduino/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 解决JUnit中的重复测试习惯用法_Java_Unit Testing_Coding Style_Junit_Xunit - Fatal编程技术网

Java 解决JUnit中的重复测试习惯用法

Java 解决JUnit中的重复测试习惯用法,java,unit-testing,coding-style,junit,xunit,Java,Unit Testing,Coding Style,Junit,Xunit,我有两个案例对我来说似乎是同一个问题,尽管它们是完全不同的情况: 1) 我正在测试对象对数据库的读写。因为我每次都在清理和重建对象,所以写测试需要读取以确认每个字段的写入,而读测试是先写入,所以测试结果看起来完全相同。但是我不想让接口中的一个主要方法未经测试 2) 在一个小得多的例子中,我正在为一个小数据对象测试copy()方法和equals()方法。copy()方法使用equals()测试自身,equals()方法针对副本进行测试。同样,测试是重复的 我觉得我在这里遗漏了一些东西,没有创建大量

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

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

2) 在一个小得多的例子中,我正在为一个小数据对象测试copy()方法和equals()方法。copy()方法使用equals()测试自身,equals()方法针对副本进行测试。同样,测试是重复的


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

作为一种表面测试,您所做的很好。毕竟,您要做的是断言write方法和read方法是互补的,当您写入和读取时,您将获得一个相等的对象(这同样适用于copy和equals)
不幸的是,正如你已经知道的那样,如果没有额外的工作,我不认为你能走得更深。测试应该非常简单,不需要额外的测试,除非您编写第二个写和读的实现,否则您必须手工操作。

对我来说,这种测试是一种代码味道。问题总是:这个测试到底测试什么?对于这个测试,你信任什么,不信任什么

对我来说,你不能同时相信read()和write(),它们可能在同一个类中,由同一个人编写。因此,如果您通过调用write()来测试read(),那么这不是一个好的测试,您测试的是write()和read()是同步的,而不是它们做了应该做的事情

在第二个示例中,您正在测试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()写入数据库,并比较read通过持久层和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;
}
私有列表resultSetToListMap(ResultSet ResultSet)引发SQLException{
int columnCount=resultSet.getMetaData().getColumnCount();
列表=新的ArrayList();
while(resultSet.next()){
Map Map=newlinkedhashmap();

对于(int i=1;我希望这是一个糟糕的做法,而不是代码气味。这些测试实际上对我来说非常有效。我可能有点不同意你的观点,我对我的重复问题没有一个概念性的答案,但感谢你的所有思考和努力,它给了我一些好主意。这款iPad不允许我分开段落,所以我很高兴我有几点意见……“我到底在测试什么?”帮助我回答equals/copy问题。我正在尝试测试副本,所以我需要进一步分解它,而不仅仅是使用equals。你的反例描述的基本上是一个模拟。如果我对代码了解不够,不知道它是否在外部连接,那么事情就真的失控了。你的建议基本上是编写一个单独的持久性层,这是我试图通过使用Hibernate首先解决的问题。我能想到的任何通用解决方案,如按列阅读和测试,都将是太多的工作和脆弱的(列顺序)。也就是说,我喜欢在DB中测试行以进行写测试的想法。这让我可以在不过火的情况下进行不同的测试。我信任Hibernate,但我不信任每个字段的映射,因此我确实需要在写测试或读测试中测试每个字段。再次感谢您。