【问题标题】:HashSet in unit tests单元测试中的 HashSet
【发布时间】:2011-08-12 15:03:13
【问题描述】:

我有一堆方法返回 HashSet。我希望我的单元测试检查这些对象的状态,即确认someObject.getName() == "foobar"

但是,哈希集迭代器顺序无法保证,因此我的单元测试有时会失败。我该如何为这样的事情编写单元测试?

例如:

@Test
    public void testRowsToBeRead(){
        HashSet<SomeObject> rows = new SomeObject().read();
        assertEquals(19, rows.size());

        for(SomeObject r:rows){
            //How do I confirm contents?
        }
    }

我想我可能太早接受了答案。

我现在遇到的问题是我已经实现了 equals 方法,该方法在每个设计中只检查对象中的 2 个字段(它正在模仿一个 DB 表)。 但是在我的单元测试中,我想检查所有不属于我的字段,例如描述等。因此,如果交换了 2 个字段并且这些字段不在我的 equals 实现中,则单元测试会给出误报。

【问题讨论】:

    标签: java junit hashset


    【解决方案1】:

    我的做法:

    public void testRowsToBeRead(){
        HashSet<SomeObject> expectedRows = new HasSet<SomeObject();
        expectedRows.add(new SomeObject("abc"));
        expectedRows.add(new SomeObject("def"));
    
        HashSet<SomeObject> rows = new SomeObject().read();
    
        // alternative 1
        assertEquals(19, rows.size());
    
        for(SomeObject r:rows){
            if (!expectedRows.contains(r)) {
                // test failed
            }
        }
    
        // alternative 2
        assertTrue(expectedRows.equals(rows));
    }
    

    要依赖此测试,您可能需要其他单元测试来确认 SomeObjectequalshashCode 方法可以正常工作...

    根据您的一个 cmets 进行编辑

    如果要检查不属于equals 合约的字段,则必须遍历集合:

    public void testRowsToBeRead(){
        HashSet<SomeObject> expectedRows = new HasSet<SomeObject();
        expectedRows.add(new SomeObject("a", "a1"));
        expectedRows.add(new SomeObject("b", "b1"));
    
        HashSet<SomeObject> rows = new SomeObject().read();
    
        for(SomeObject r : rows) {
            SomeObject expected = expectedRows.get(r); // equals and hashCode must still match
    
            if (expected == null) {
                // failed
            }
    
            if (!expected.getField1().equals(r.getField1()) && !expected.getField2().equals(r.getField2())) {
                // failed
            }
        }
    }
    

    在上面的例子中SomeObjectequals可能看起来像这样,它只检查field1

    @Override
    public boolean equals(Object other) {
        return this.getField1().equals( ((SomeObject) other).getField1() );
    }
    

    毫无疑问,根据您的具体用例,这可能会变得更加复杂。希望这会有所帮助...

    【讨论】:

    • equalshashCode 必须正确实施才能使用这种方法(并使用 HashSet)。
    • 我已经进行了 equals 和 hashcode 单元测试,所以我认为这正是我想要的。
    • HashSet#equals 不会做同样的事情吗?即if (!expcectedRows.equals(rows)) { /* fail */ }
    • @Arturs Licis:+1,根据 JavaDOc 你是对的,它的行为应该是一样的......节省了四行代码:-)
    • 我现在遇到的问题是我已经实现了 equals 方法,该方法在每个设计中仅检查对象中的 2 个字段(它正在模仿 DB 表)。但是在我的单元测试中,我想检查所有不属于我的字段,例如描述等。因此,如果交换了 2 个字段并且这些字段不在我的 equals 实现中,则单元测试会给出误报。
    【解决方案2】:

    您可以使用LinkedHashSet保证订单。

    【讨论】:

    • 谢谢。这需要我改变实际的方法。我可能会在未来的某个时候这样做,但现在我只是想让我的单元测试继续下去。
    【解决方案3】:

    尝试使用 assertThat:

    Assert.assertThat(r.getName(), AnyOf.anyOf(Is.is("foobar1"), Is.is("foobar2"), ...));
    

    【讨论】:

      【解决方案4】:

      您可以在几乎任何带有 TestNG 的集合上使用 Assert.assertEquals(),也可以使用 JUnit。

      如果您想自己滚动,请从预期集中删除实际集的所有元素,并在完成后断言预期集的大小为零。

      【讨论】:

        【解决方案5】:

        我推荐使用HashSet.equals(Object)

        JavaDoc 说:

        这个实现首先检查指定的对象是否是这个集合;如果是,则返回 true。然后,它检查指定的对象是否是一个大小与该集合大小相同的集合;如果不是,则返回 false。如果是,则返回 containsAll((Collection) o)。

        所以我觉得“家”的“另类2”就够了。

        加:虽然 HashSet 不保证顺序,但相等的 HashSet 的顺序和大小相同。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-12-13
          • 2013-02-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多