【问题标题】:How can I do unit test for hashCode()?如何对 hashCode() 进行单元测试?
【发布时间】:2010-12-15 12:12:03
【问题描述】:

如何测试unit testing 中的hashCode() 函数?

public int hashCode(){
    int result = 17 + hashDouble(re);
    result = 31 * result + hashDouble(im);
    return result;
}

【问题讨论】:

    标签: java unit-testing junit hashcode


    【解决方案1】:

    每当我重写 equals 和 hash 代码时,我都会按照 Joshua Bloch 在“Effective Java”第 3 章中的建议编写单元测试。我确保 equals 和 hash 代码是自反的、对称的和传递的。我还确保“不等于”适用于所有数据成员。

    当我检查对 equals 的调用时,我还要确保 hashCode 的行为符合其应有的行为。像这样:

    @Test
    public void testEquals_Symmetric() {
        Person x = new Person("Foo Bar");  // equals and hashCode check name field value
        Person y = new Person("Foo Bar");
        Assert.assertTrue(x.equals(y) && y.equals(x));
        Assert.assertTrue(x.hashCode() == y.hashCode());
    }
    

    【讨论】:

    • 除此之外,您可以补充一点,测试对非关键字段的修改不会导致生成修改后的 hashCode 是合理的。此外,对关键字段的修改确实会导致修改 hashCodes。
    • 我认为我们不应该测试另一种方法,因为这个测试只是针对哈希码,所以必须只比较哈希码,其余代码应该进行等值测试,应该单独测试
    • 六年后,我仍然不同意你的观点。我看不出有什么区别。它们需要一起被覆盖;它们可以一起测试。如果您需要单独的测试,请自行淘汰。
    • @duffymo 你为什么要用 x 和 y 测试 .equals?您是否应该测试 x.hashCode() == y.hashCode() && y.hashCode() == x.hashcode() 的对称属性???
    • 不。我已经知道 == 是对称的。你意识到这个问题和答案已经有将近十年的历史了吗?
    【解决方案2】:

    当您编写一般的数学函数(如哈希码)时,您会在测试中测试一些示例,直到您确信该函数按预期工作。有多少示例取决于您的功能。

    对于哈希码函数,我认为您至少要测试两个被认为相等的不同对象具有相同的哈希码。喜欢

    assertNotSame(obj1, obj2); // don't cheat
    assertEquals(obj1.hashcode(), obj2.hashcode());
    

    您还应该测试两个不同的值是否具有不同的哈希码,以避免像return 1; 那样实现hashcode()

    【讨论】:

    【解决方案3】:

    hashCode 被覆盖,以使具有相同字段的实例与 HashSet/HashMap 等相同。 所以 Junit 测试应该断言两个具有相同值的不同实例返回相同的 hashCode。

    【讨论】:

    • 一次测试很有用,但测试数百万个值会更有用,而且仍然需要不到一秒钟的时间。
    【解决方案4】:

    创建许多(数百万个)可复制的随机对象,并将所有 hashCodes 添加到一个 Set 中,并检查您得到的几乎和许多 unqiue 值作为生成 id 的数量。为了使它们可随机复制,请使用固定的随机种子。

    另外检查您是否可以将这些项目添加到 HashSet 并再次找到它们。 (使用具有相同值的不同对象)

    确保您的 equals() 与您的 hashCode() 行为相匹配。我还会检查您的字段是否都是最终字段。

    【讨论】:

    • 我对此投了反对票,原因很简单,即在单元测试中添加随机性是一件坏事——因为你想知道的第一件事是为什么测试失败了——如果它的输入是随机的,这是非常困难的。另外,您可能需要通过哈希码方法运行数十亿个对象以获得信心,这可能意味着您的单元测试需要很长时间才能运行,这也是一件坏事。
    • 没有给出反对票的理由。解释会很有帮助。
    • @Visage,使用非随机数据如何告诉您测试失败的原因,您所需要的只是可重现性来帮助诊断失败的测试。任何现实的测试驱动开发都无法达到您声称的证明水平。但是,您可以在测试失败时说您有问题。
    • @Visage,数十亿并没有那么多,但数百万会发现大多数错误。只需一次测试就可以发现经常令人惊讶的错误。
    • 我不认为这是一个糟糕的答案。如果使用随机性来建立统计资料,那为什么不好呢?运行时间的长短不应成为是否编写测试的决定因素。可以将您的测试划分为您每次运行的快速测试和运行时间较长的测试,这些测试由您自行决定,除非进行更改,否则不需要运行。在我看来,彼得的回答不值得投反对票。
    【解决方案5】:

    我认为没有必要对哈希码方法进行单元测试。特别是如果它是由您的 IDE 或 HashCodeBuilder (apache commons) 生成的

    【讨论】:

    • 阅读代码可能是确保代码有意义的最佳检查。即通过反复试验很难找到病态病例。
    【解决方案6】:

    除了@duffymo 测试哈希码是自反的、对称的和传递的,另一种测试方法是通过“映射”,这是哈希码真正派上用场的地方。

     @Test
    public void testHashcode() {
        Person p1 = new Person("Foo Bar"); 
        Person p2 = new Person("Foo Bar");
        Map<Person, String> map = new HashMap<>();
        map.put(p1, "dummy");
        Assert.assertEquals("dummy", map.get(p2));
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-01-08
      • 2019-11-02
      • 1970-01-01
      • 1970-01-01
      • 2013-09-30
      • 2019-01-05
      • 2011-03-16
      • 2013-01-02
      相关资源
      最近更新 更多