Java 如何对hashCode()进行单元测试?

Java 如何对hashCode()进行单元测试?,java,unit-testing,junit,hashcode,Java,Unit Testing,Junit,Hashcode,如何在中测试hashCode()函数 我认为没有必要对hashcode方法进行单元测试。特别是如果它是由IDE或(apache commons)生成的,请创建许多(数百万)可复制的随机对象,并将所有哈希代码添加到一个集合中,然后检查是否得到几乎和许多unqiue值作为生成ID的数量。要使它们随机繁殖,请使用固定的随机种子 另外,请检查是否可以将这些项添加到哈希集中并再次找到它们。(使用具有相同值的不同对象) 确保equals()与hashCode()行为匹配。我还要检查您的字段是否都是最终字段。

如何在中测试hashCode()函数


我认为没有必要对hashcode方法进行单元测试。特别是如果它是由IDE或(apache commons)生成的,请创建许多(数百万)可复制的随机对象,并将所有哈希代码添加到一个集合中,然后检查是否得到几乎和许多unqiue值作为生成ID的数量。要使它们随机繁殖,请使用固定的随机种子

另外,请检查是否可以将这些项添加到哈希集中并再次找到它们。(使用具有相同值的不同对象)


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

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

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

当我检查对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());
}

当你编写一个数学函数时(比如散列码),你需要在测试中测试一些例子,直到你确信这个函数能按预期工作为止。有多少示例取决于您的函数

对于散列码函数,我认为您至少要测试两个被认为相等的不同对象是否具有相同的散列码。像

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

此外,您应该测试两个不同的值是否具有不同的哈希代码,以避免实现
hashcode()
类似
return1

除了@duffymo测试hashcode的自反性、对称性和传递性外,另一种测试方法是通过“Map”进行测试,这是hashcode真正方便使用的地方

 @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));
}
@测试
public void testHashcode(){
人员p1=新人员(“Foo Bar”);
人员p2=新人员(“Foo Bar”);
Map Map=newhashmap();
映射放置(p1,“虚拟”);
Assert.assertEquals(“dummy”,map.get(p2));
}

阅读代码可能是确保其有意义的最佳检查。i、 e.通过尝试和错误很难找到符合逻辑的案例。我对此投了反对票,原因很简单,在单元测试中添加随机性是一件坏事——因为你想知道的第一件事是测试失败的原因——如果它的输入是随机的,这是非常困难的。此外,您可能需要通过hashcode方法运行数十亿个对象才能获得信心,这可能意味着您的单元测试需要很长时间才能运行,这也是一件坏事。没有给出否决票的理由。解释会很有帮助。@Visage,如何使用非随机数据告诉您测试失败的原因,您所需要的只是再现性来帮助诊断失败的测试。任何实际的测试驱动开发都无法达到您声称的证明级别。然而,当测试失败时,你可以说你有问题。@Visage,数十亿并不多,但数百万人会发现大多数错误。仅仅一次测试就可以发现一个经常令人惊讶的错误。我不认为这是一个糟糕的答案。如果随机性被用来建立一个统计轮廓,为什么会那么糟糕?运行所需的时间长度不应成为是否编写测试的决定因素。您可以将测试分为每次运行的快速测试和长时间运行的测试,这些测试由您自行决定,除非进行更改,否则不需要运行。在我看来,Peter的答案不值得投反对票。一个测试是有用的,但测试数百万个值会更有用,而且仍然需要不到一秒钟的时间。除此之外,您可以补充一点,测试对非关键字段的修改不会导致生成修改的哈希代码是合理的。此外,对关键字段的修改确实会导致修改的哈希代码。我认为我们不应该测试另一种方法,因为此测试只针对哈希代码,所以必须只比较哈希代码,其余的代码应该进行相等测试,并且应该在X年后单独测试,我仍然不同意你的观点。我看不出有什么不同。它们需要一起被推翻;它们可以一起测试。如果你需要单独的测试,那就把你自己击倒。@duffymo你为什么要测试。等于x和y?您是否应该测试x.hashCode()==y.hashCode()&&y.hashCode()==x.hashCode()?否。我已经知道==是对称的。您知道这个问题和答案已经有十年的历史了吗?请注意,Java不需要不相等的对象来获得不同的结果。因此,在某些情况下,两个不相等的对象的哈希代码可能是相同的,而不会违反Java准则。
 @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));
}