Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test for equality of complex object graphs?

Tags:

Say I have a unit test that wants to compare two complex for objects for equality. The objects contains many other deeply nested objects. All of the objects' classes have correctly defined equals() methods.

This isn't difficult:

@Test public void objectEquality() {     Object o1 = ...     Object o2 = ...      assertEquals(o1, o2); } 

Trouble is, if the objects are not equal, all you get is a fail, with no indication of which part of the object graph didn't match. Debugging this can be painful and frustrating.

My current approach is to make sure everything implements toString(), and then compare for equality like this:

    assertEquals(o1.toString(), o2.toString()); 

This makes it easier to track down test failures, since IDEs like Eclipse have a special visual comparator for displaying string differences in failed tests. Essentially, the object graphs are represented textually, so you can see where the difference is. As long as toString() is well written, it works great.

It's all a bit clumsy, though. Sometimes you want to design toString() for other purposes, like logging, maybe you only want to render some of the objects fields rather than all of them, or maybe toString() isn't defined at all, and so on.

I'm looking for ideas for a better way of comparing complex object graphs. Any thoughts?

like image 355
skaffman Avatar asked Sep 11 '09 15:09

skaffman


People also ask

How do you assert if two objects are equal?

If the two objects have the same values, equals() will return true . In the second comparison, equals() checks to see whether the passed object is null, or if it's typed as a different class. If it's a different class then the objects are not equal. Finally, equals() compares the objects' fields.

How do you know if an object is equal?

Objects are equal when they have the same state (usually comparing variables). Objects are identical when they share the class identity. For example, the expression obj1==obj2 tests the identity, not equality.

How do you check for equality of two objects in Junit?

assertEquals() calls equals() on your objects, and there is no way around that. What you can do is to implement something like public boolean like(MyClass b) in your class, in which you would compare whatever you want. Then, you could check the result using assertTrue(a. like(b)) .

How do we compare objects?

Comparing Objects ¶ When using the comparison operator ( == ), object variables are compared in a simple manner, namely: Two object instances are equal if they have the same attributes and values (values are compared with == ), and are instances of the same class.


1 Answers

The Atlassian Developer Blog had a few articles on this very same subject, and how the Hamcrest library can make debugging this kind of test failure very very simple:

  • How Hamcrest Can Save Your Soul (part 1)
  • Hamcrest saves your soul - Now with less suffering! (part 2)

Basically, for an assertion like this:

assertThat(lukesFirstLightsaber, is(equalTo(maceWindusLightsaber))); 

Hamcrest will give you back the output like this (in which only the fields that are different are shown):

Expected: is {singleBladed is true, color is PURPLE, hilt is {...}}   but: is {color is GREEN} 
like image 140
matt b Avatar answered Oct 06 '22 04:10

matt b