Technique to automatically check consistency of eq

2019-01-23 03:11发布

I'm well aware of the contractual needs to make sure that hashCode is consistent with equals and that equals is consistent with compareTo. However, this is often violated in practice. Are there any tools, techniques, or libraries that can test for this consistency automatically?

I suspect unfortunately that the answer is "no," but it would be useful to be able to have a unit test for this sort of thing that could make use of a library call or framework rather than needing to write a custom test by hand for each case where it is important.

In case it's not clear what I mean by consistency, for hashCode and equals I refer to the following:

If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.

For equals and compareTo I refer to the following:

The natural ordering for a class C is said to be consistent with equals if and only if e1.compareTo(e2) == 0 has the same boolean value as e1.equals(e2) for every e1 and e2 of class C.

5条回答
我命由我不由天
2楼-- · 2019-01-23 03:51

If you're using JUnit, the extensions package has the EqualsHashCodeTestCase, which fully tests both equals and hashCode for everything outlined in the Java spec (reflexive, transitive, symmetric, etc). All you have to do is provide an equal and not equal object for the parent class to use for checking.

Since the CompareTo method is part of the Comparable interface, it's actually split out into another test case - the ComparabilityTestCase. This takes three objects - one of lesser value, equal value, and greater value. Override these and the parent class will take care of the rest.

查看更多
beautiful°
3楼-- · 2019-01-23 03:53

Guava's tests have a utility called EqualsTester which we use as an everyday part of our unit tests to test equals and hashCode. Its use looks like

new EqualsTester()
  .addEqualityGroup("hello", "h" + "ello")
  .addEqualityGroup("world", "wor" + "ld")
  .addEqualityGroup(2, 1 + 1)
  .testEquals();

which tests that all values in the same group are equal and have the same hash codes, that different groups are not equal, and that various other invariants are all satisfied. You could either use it yourself, or just borrow its ideas.

I would be extremely surprised if it was possible to test without generating or explicitly specifying test values, just because that seems very likely equivalent to the halting problem.

查看更多
我命由我不由天
4楼-- · 2019-01-23 03:53

There is a very cool tool called Korat that can do exhaustive searches to check the correctness of Java classes for small cases. It actually looks at the code that's executed in order to build all the different test cases of a given size that the program can actually distinguish between. I don't know how useful it is in large cases, but for many programs it can be used to automatically check whether cases like this work correctly.

Hope this helps!

查看更多
The star\"
5楼-- · 2019-01-23 03:54

I have written some utility methods to help unit testing hashCode and equals methods:

http://softsmithy.sourceforge.net/devlib/docs/api/org/softsmithy/devlib/junit/Tests.html

The library is Open Source and can be downloaded from here: http://sourceforge.net/projects/softsmithy/files/softsmithy-devlib/v0.1/

or with Maven:

    <dependency>
        <groupId>org.softsmithy.devlib</groupId>
        <artifactId>devlib-core</artifactId>
        <version>0.1</version>
        <scope>test</scope>
    </dependency>
查看更多
叼着烟拽天下
6楼-- · 2019-01-23 04:06

I’ve recently used meanbean (http://meanbean.sourceforge.net/) to automatically test a class for the equals() and hashCode() contracts (plus setter/getter pairs).

"Mean Bean:

1. Tests that the getter and setter method pairs of a JavaBean/POJO function correctly.

2. Verifies that the equals and hashCode methods of a class comply with the Equals Contract and HashCode Contract respectively.

3. Verifies property significance in object equality."

I still have a lot of questions specific to meanbean: whether it verifies equals() and hashCode() consistency. Plus I haven’t tried hard to defeat it. I believe it has no support for compareTo(). And I haven’t tried alternatives. Interested in other's experience.

查看更多
登录 后发表回答