JUnit/TestNG tip: Diffing Lists

A little cheap and cheerful JUnit/TestNG tip…

Problem: You’ve got two lists that you want to compare using assertEquals(). But when the assertion fails, the error message kinda sucks.

java.lang.AssertionError: expected:<[Person{name=Joe,starsign=Virgo,sex=Male}, Person{name=Jaimie,starsign=Libra,sex=Female}, Per
son{name=Ewan,starsign=Capricorn,sex=Male}]> but was:<[Person{name=Joe,starsign=Virgo,sex=Male}, Person{name=Jaimie,starsign=Scor
pio,sex=Female}]>
   at org.junit.Assert.fail(Assert.java:74)
   at org.junit.Assert.failNotEquals(Assert.java:448)
   at org.junit.Assert.assertEquals(Assert.java:102)
   ...

It’s really tricky to see exactly where the differences are in the list.

Solution: Join both the lists into a string, delimited by newlines and assert that instead. That will force your IDE’s multiline differ to kick in.

junit-diff(click image to see the rest of it)

This relies on having a sensible toString() method on your list items.

If your IDE doesn’t do this, or you can’t run your tests from your IDE, you should really get that seen to.

Here’s a method to do it:

public static <T> void assertList(List<T> actual, T... expected) {
  assertEquals(join(expected, "\n"), join(actual, "\n"));
}

That’s all. Now get back to work.

  • Trackback are closed
  • Comments (2)
  1. An assumption here is that your .equals() is checking the same state that your.toString() is displaying. Most of the time it’s true, but when it’s not you’re getting a bad test result.

  2. There is some improved support for list comparisons in Hamcrest now. For example, this code:

    List actual = Arrays.asList(“name=Joe”,”starsign=Virgo”,”sex=Male”);
    assertThat(actual, Matchers.contains(“name=Joe”, “starsign=Libra”, “sex=Female”));

    will generate:

    Expected: iterable over [“name=Joe”, “starsign=Libra”, “sex=Female”]
    but: item 1: was “starsign=Virgo”

Comments are closed.
%d bloggers like this: