From: Eric Sosman on 19 Mar 2010 08:26 On 3/19/2010 1:40 AM, Daniel Pitts wrote: > On 3/18/2010 5:44 PM, Eric Sosman wrote: >> [...] >> Sorry if I wasn't clear: By referring to the "pair," I meant >> trying to test that x.equals(y) -> x.hashCode() == y.hashCode(), >> or that x.hashCode() != y.hashCode() -> !x.equals(y). Testing >> equals() alone may make sense. Testing hashCode() alone almost >> certainly doesn't. The implications must hold, but I'm not >> convinced testing is the right way to verify that they do. >> > if your objects behavior depends on correct functioning of that method > pair, then you should definitely unit test them. Usually it's not the object's own behavior, but the behavior of a HashMap or similar that might use your object as a key, possibly in some circumstance you didn't anticipate. > At the very least, testing the first is important (x.equals(y) -> > x.hashCode() == y.hashCode()). Yeah, but how do you test it and have confidence? You can create a bunch of equal objects and compare hashCodes, but how do you know you've covered the space of all glitches? For example, you might generate the String "Hello" as a literal and again by assembling it in a StringBuilder, and find that the two Strings' hashCodes are equal; that's fine. But what if they had been six characters long instead of five, or if they'd had some other genesis? "How do you know when you've tested enough?" is, of course, a question that besets all testing. But with respect to the equals/hashCode pair, I suggest that code inspection is a superior approach, because it can lead to complete confidence instead of to "Well, I've never seen it misbehave." If you can show that 1) The result of the equals() method depends only on the instance variables of the two objects, and not on any "external" datum (once class identity is satisfied), and 2) The result of the hashCode() method depends only on the instance variables of one instance, and 3) The variables used by hashCode() are a subset of those used by equals() .... then you've *proved* the methods consistent. I submit that a solid proof is preferable to anything testing can yield, and that these methods are nearly always simple enough to make proof not merely feasible but straightforward. > Actually, if you test that for all edge/general cases, Knowing where the edge cases are requires knowledge of the way the methods are implemented, or at the very least an informed guess about the implementation. If you're willing to examine the code to guide the writing of the test, it seems silly not to go ahead and do the proof. Ah, well: Different strokes for different folks. > then the second > one is probably irrelevant (or redundant) The two implications are logically equivalent. There's an old story about two friends who set out to test "All crows are black." The first spent a lot of time and money, traveled the wide world over looking for crows, and recorded that every crow he saw was black. "Testing can't *prove* crowblackness," he said, "but by examining a large sample of crows and finding all of them black I have increased my level of confidence in the proposition." The second guy was a logician, and observed that the statement "All non-black things are non-crows" is logically equivalent to the original: Prove either, and you have proved the other. So he just sat back in his easy chair and let his eyes wander to non-black things in his field of view, observing that every non-black thing he saw was a non-crow. "Testing can't *prove* nonblacknoncrowness," he said, "but by examining a large sample of non-black things and finding all of them to be non-crows I have increased my level of confidence in both propositions. Plus, I've saved a lot of time and money and have been lavishing it on my absent friend's main squeeze, to our considerable enjoyment." More prosaically, one of the implications might be easier to test than the other. -- Eric Sosman esosman(a)ieee-dot-org.invalid
From: Patricia Shanahan on 19 Mar 2010 09:08 Graham Cox wrote: > Rhino <no.offline.contact.please(a)example.com> writes: > >> I've been lucky enough not to get burned by one of those yet - at least as >> far as I know! - but you make a good point. Murphy's Laws, right? Anything >> that can go wrong, will go wrong. >> >> It probably makes sense to test even really trivial-looking code.... >> > I tend to think that any function with more than 2 lines of code should be > unit tested. This means that getters and setters are generally exempt *unless > they do something*. Specifically it means that the setters that do data > validation first should be tested, but the setters that do nothign more than > store the value to a member variable can be ignored... > > I use different criteria. The Eclipse "Source" code generation seems to be well tested. If I merely told Eclipse to generate a setter or getter, or the equals/hashCode pair, I don't write a test. If I wrote a getter or setter myself, it needs testing. I'm fully capable of making a mistake in a single line of code. Patricia
From: bugbear on 19 Mar 2010 11:32 Patricia Shanahan wrote: > I'm fully capable of making a > mistake in a single line of code. Now you're just bragging ;-) BugBear
From: Graham Cox on 19 Mar 2010 11:49 Patricia Shanahan <pats(a)acm.org> writes: > I use different criteria. The Eclipse "Source" code generation seems to > be well tested. If I merely told Eclipse to generate a setter or getter, > or the equals/hashCode pair, I don't write a test. If I wrote a getter > or setter myself, it needs testing. I'm fully capable of making a > mistake in a single line of code. Fair point, but I was more getting at the fact that I *do* unit test generated functions like equals and hashCode, simply because the class often changes after they were generated and they are no longer valid. Just because the code was correct at the time of writing doesn't mean it will always remain so... -- Graham Cox
From: Tom Anderson on 19 Mar 2010 12:17
On Fri, 19 Mar 2010, Eric Sosman wrote: > "How do you know when you've tested enough?" is, of course, a > question that besets all testing. But with respect to the > equals/hashCode pair, I suggest that code inspection is a superior > approach, because it can lead to complete confidence instead of to > "Well, I've never seen it misbehave." How often do you propose to do this inspection, and how you propose to ensure that it is done? tom -- I thought it would be fun if I could get the baby do do communism stuff with me, but when I tried to get her attention she crawled over to the VCR and put a breadstick into it. That's not communism! That's anarchy! -- Philippe |