87

Is there a jUnit parallel to NUnit's CollectionAssert?

Neuron
  • 5,141
  • 5
  • 38
  • 59
ripper234
  • 222,824
  • 274
  • 634
  • 905

5 Answers5

131

Using JUnit 4.4 you can use assertThat() together with the Hamcrest code (don't worry, it's shipped with JUnit, no need for an extra .jar) to produce complex self-describing asserts including ones that operate on collections:

import static org.junit.Assert.assertThat;
import static org.junit.matchers.JUnitMatchers.*;
import static org.hamcrest.CoreMatchers.*;

List<String> l = Arrays.asList("foo", "bar");
assertThat(l, hasItems("foo", "bar"));
assertThat(l, not(hasItem((String) null)));
assertThat(l, not(hasItems("bar", "quux")));
// check if two objects are equal with assertThat()

// the following three lines of code check the same thing.
// the first one is the "traditional" approach,
// the second one is the succinct version and the third one the verbose one 
assertEquals(l, Arrays.asList("foo", "bar")));
assertThat(l, is(Arrays.asList("foo", "bar")));
assertThat(l, is(equalTo(Arrays.asList("foo", "bar"))));

Using this approach you will automagically get a good description of the assert when it fails.

koppor
  • 19,079
  • 15
  • 119
  • 161
Joachim Sauer
  • 302,674
  • 57
  • 556
  • 614
  • 1
    Ooh, I hadn't realised hamcrest had made it into the junit distro. Go Nat! – skaffman Jul 06 '09 at 12:49
  • If I want to assert l is composed of items ("foo", "bar"), but no other items exists - is there some easy syntax for that? – ripper234 Jul 06 '09 at 12:57
  • Use the above code snippet and throw in an additional assertTrue(l.size() == 2) – aberrant80 Jul 06 '09 at 13:12
  • 4
    Meh, ugly. In NUnit that's CollectionAssert.AreEqual( Collection expected, Collection actual ); – ripper234 Jul 06 '09 at 14:08
  • Isn't that just assertTrue(collection1.equals(collection2)); ? – Esko Jul 06 '09 at 14:58
  • You are free to write your own CollectionAssert.AreEqual(Collection col1, Collection col2) using example above. You'll needed about 5 minutes to made this. – Vanger Jul 06 '09 at 15:00
  • 1
    Google have found another Stackoverflow answer that I was looking for! – Mykola Golubyev Aug 06 '09 at 15:15
  • "the second one is the succinct version" - it's 1 character less succint than the 'traditional' approach! – bacar May 09 '12 at 16:01
  • Note that depending on what you are testing, you may want `contains`, `containsInAnyOrder`, or `hasItems`. `contains` and `containsInAnyOrder` fail if there are unexpected entries in the list. `contains` fails if the list is not in the same order. See [this answer](https://stackoverflow.com/a/33840532/710377) for more details. – meustrus Oct 14 '19 at 21:00
4

Not directly, no. I suggest the use of Hamcrest, which provides a rich set of matching rules which integrates nicely with jUnit (and other testing frameworks)

koppor
  • 19,079
  • 15
  • 119
  • 161
skaffman
  • 398,947
  • 96
  • 818
  • 769
  • This does not compile for some reason (see http://stackoverflow.com/questions/1092981/hamcrests-hasitems): ArrayList actual = new ArrayList(); ArrayList expected = new ArrayList(); actual.add(1); expected.add(2); assertThat(actual, hasItems(expected)); – ripper234 Jul 07 '09 at 15:23
2

Take a look at FEST Fluent Assertions. IMHO they are more convenient to use than Hamcrest (and equally powerful, extensible etc) and have better IDE support thanks to fluent interface. See https://github.com/alexruiz/fest-assert-2.x/wiki/Using-fest-assertions

2

Joachim Sauer's solution is nice but doesn't work if you already have an array of expectations that you want to verify are in your result. This might come up when you already have a generated or constant expectation in your tests that you want to compare a result to, or perhaps you have multiple expectations you expect to be merged in the result. So instead of using matchers you can can just use List::containsAll and assertTrue For Example:

@Test
public void testMerge() {
    final List<String> expected1 = ImmutableList.of("a", "b", "c");
    final List<String> expected2 = ImmutableList.of("x", "y", "z");
    final List<String> result = someMethodToTest(); 

    assertThat(result, hasItems(expected1)); // COMPILE ERROR; DOES NOT WORK
    assertThat(result, hasItems(expected2)); // COMPILE ERROR; DOES NOT WORK

    assertTrue(result.containsAll(expected1));  // works~ but has less fancy
    assertTrue(result.containsAll(expected2));  // works~ but has less fancy
}
gavs
  • 266
  • 3
  • 6
  • You can always use `hasItems(expected1.toArray(new String[expected1.size()]))`. It will give you better failure messages. – meustrus Oct 14 '19 at 21:14
1

Using JUnit 5

Assertions.assertIterableEquals(Iterable<?> expected, Iterable<?> actual)
Marcus Voltolim
  • 413
  • 4
  • 12