Assert equals between 2 Lists in Junit

268,546

Solution 1

For junit4! This question deserves a new answer written for junit5.

I realise this answer is written a couple years after the question, probably this feature wasn't around then. But now, it's easy to just do this:

@Test
public void test_array_pass()
{
  List<String> actual = Arrays.asList("fee", "fi", "foe");
  List<String> expected = Arrays.asList("fee", "fi", "foe");

  assertThat(actual, is(expected));
  assertThat(actual, is(not(expected)));
}

If you have a recent version of Junit installed with hamcrest, just add these imports:

import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;

http://junit.org/junit4/javadoc/latest/org/junit/Assert.html#assertThat(T, org.hamcrest.Matcher)

http://junit.org/junit4/javadoc/latest/org/hamcrest/CoreMatchers.html

http://junit.org/junit4/javadoc/latest/org/hamcrest/core/Is.html

Solution 2

Don't transform to string and compare. This is not good for perfomance. In the junit, inside Corematchers, there's a matcher for this => hasItems

List<Integer> yourList = Arrays.asList(1,2,3,4)    
assertThat(yourList, CoreMatchers.hasItems(1,2,3,4,5));

This is the better way that I know of to check elements in a list.

Solution 3

For JUnit 5

you can use assertIterableEquals :

List<String> numbers = Arrays.asList("one", "two", "three");
List<String> numbers2 = Arrays.asList("one", "two", "three");

Assertions.assertIterableEquals(numbers, numbers2);

or assertArrayEquals and converting lists to arrays :

List<String> numbers = Arrays.asList("one", "two", "three");
List<String> numbers2 = Arrays.asList("one", "two", "three");
Assertions.assertArrayEquals(numbers.toArray(), numbers2.toArray());

Solution 4

assertEquals(Object, Object) from JUnit4/JUnit 5 or assertThat(actual, is(expected)); from Hamcrest proposed in the other answers will work only as both equals() and toString() are overrided for the classes (and deeply) of the compared objects.

It matters because the equality test in the assertion relies on equals() and the test failure message relies on toString() of the compared objects.
For built-in classes such as String, Integer and so for ... no problem as these override both equals() and toString(). So it is perfectly valid to assert List<String> or List<Integer> with assertEquals(Object,Object).
And about this matter : you have to override equals() in a class because it makes sense in terms of object equality, not only to make assertions easier in a test with JUnit.
To make assertions easier you have other ways.
As a good practice I favor assertion/matcher libraries.

Here is a AssertJ solution.

org.assertj.core.api.ListAssert.containsExactly() is what you need : it verifies that the actual group contains exactly the given values and nothing else, in order as stated in the javadoc.

Suppose a Foo class where you add elements and where you can get that.
A unit test of Foo that asserts that the two lists have the same content could look like :

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;

@Test
void add() throws Exception { 
   Foo foo = new Foo();
   foo.add("One", "Two", "Three");
   Assertions.assertThat(foo.getElements())
             .containsExactly("One", "Two", "Three");
}

A AssertJ good point is that declaring a List as expected is needless : it makes the assertion straighter and the code more readable :

Assertions.assertThat(foo.getElements())
         .containsExactly("One", "Two", "Three");

But Assertion/matcher libraries are a must because these will really further.
Suppose now that Foo doesn't store Strings but Bars instances.
That is a very common need. With AssertJ the assertion is still simple to write. Better you can assert that the list content are equal even if the class of the elements doesn't override equals()/hashCode() while JUnit way requires that :

import org.assertj.core.api.Assertions;
import static org.assertj.core.groups.Tuple.tuple;
import org.junit.jupiter.api.Test;

@Test
void add() throws Exception {
    Foo foo = new Foo();
    foo.add(new Bar(1, "One"), new Bar(2, "Two"), new Bar(3, "Three"));
    Assertions.assertThat(foo.getElements())
              .extracting(Bar::getId, Bar::getName)
              .containsExactly(tuple(1, "One"),
                               tuple(2, "Two"),
                               tuple(3, "Three"));
}

Solution 5

This is a legacy answer, suitable for JUnit 4.3 and below. The modern version of JUnit includes a built-in readable failure messages in the assertThat method. Prefer other answers on this question, if possible.

List<E> a = resultFromTest();
List<E> expected = Arrays.asList(new E(), new E(), ...);
assertTrue("Expected 'a' and 'expected' to be equal."+
            "\n  'a'        = "+a+
            "\n  'expected' = "+expected, 
            expected.equals(a));

For the record, as @Paul mentioned in his comment to this answer, two Lists are equal:

if and only if the specified object is also a list, both lists have the same size, and all corresponding pairs of elements in the two lists are equal. (Two elements e1 and e2 are equal if (e1==null ? e2==null : e1.equals(e2)).) In other words, two lists are defined to be equal if they contain the same elements in the same order. This definition ensures that the equals method works properly across different implementations of the List interface.

See the JavaDocs of the List interface.

Share:
268,546

Related videos on Youtube

Kamal
Author by

Kamal

Updated on November 22, 2020

Comments

  • Kamal
    Kamal over 3 years

    How can I make an equality assertion between lists in a JUnit test case? Equality should be between the content of the list.

    For example:

    List<String> numbers = Arrays.asList("one", "two", "three");
    List<String> numbers2 = Arrays.asList("one", "two", "three");
    List<String> numbers3 = Arrays.asList("one", "two", "four"); 
    
    // numbers should be equal to numbers2
    //numbers should not be equal to numbers3
    
    • Thibstars
      Thibstars over 6 years
      I like to use assertArrayEquals nowadays. Use in combination with List#toArray.
    • dfrankow
      dfrankow almost 6 years
      @Thibstars - I'd upvote that as an answer.
    • ThetaSinner
      ThetaSinner over 5 years
      assertArrayEquals requires you to get arrays from your lists. You can operate directly on the list using assertIterableEquals
    • iec2011007
      iec2011007 about 4 years
      assertIterableEquals available for jUnit5 @ThetaSinner
  • Kamal
    Kamal almost 14 years
    So you mean expected.equals(a) will take care of asserting the objects that the list is holding ?
  • Paul McKenzie
    Paul McKenzie almost 14 years
    From List javadoc: Compares the specified object with this list for equality. Returns true if and only if the specified object is also a list, both lists have the same size, and all corresponding pairs of elements in the two lists are equal. (Two elements e1 and e2 are equal if (e1==null ? e2==null : e1.equals(e2)).) In other words, two lists are defined to be equal if they contain the same elements in the same order. This definition ensures that the equals method works properly across different implementations of the List interface.
  • Michael Lloyd Lee mlk
    Michael Lloyd Lee mlk almost 14 years
    This alas provides less than helpful error message. I have found it better to write a utility class which performs a loop so you can see which elements are different.
  • Bart Kiers
    Bart Kiers almost 14 years
    @mlk, perhaps, but I'm hesitant to write a custom utility method for such a thing. What about the error message I edited just now?
  • Matt N
    Matt N almost 14 years
    @mlk I agree that it might be better to write a loop to test each element so you know exactly what is different. It depends on what types of objects are in the list. If they are Strings, then just say "a="+a should be fine, but if they are complex objects (other lists, or something that doesn't have a good toString implementation), it might be easier to test them individually
  • Kamal
    Kamal almost 14 years
    So in case the list are having same objects, but in different order, this expected.equals(a) will return false.
  • Michael Lloyd Lee mlk
    Michael Lloyd Lee mlk almost 14 years
    Bart/Matt - The solution I use is I have /the loop/ but if the loop finds a difference it generates a string of the array using Apache Commons ReflectionToStringBuilder for the elements. It then does a string assert on the two generated strings (as this is colour coded in Eclipses JUnit runner) followed by a simple fail should the string assert pass. It is not a solution for every occasion but it works nicely for many.
  • Barett
    Barett almost 11 years
    Note: If you don't care about the order of the elements, you should be using a Set or Collection, not a List.
  • Catfish
    Catfish about 10 years
    System.out.println(actual == expected); will return false, but System.out.println(actual.equals(expected)); will return true.
  • djeikyb
    djeikyb about 10 years
    @Catfish yeah, that's confusing isn't it. I think I was demonstrating that the matcher is using .equals(..) instead of ==?
  • Ryan
    Ryan almost 10 years
    I agree. This library is gross. Why on earth would ListAssert.assertEquals() default to orderless?
  • yoni
    yoni over 6 years
    Should be the chosen answer, with one note: You need also to verify that there are no more items in the list besides what you want. Maybe use:Assert.assertEquals(4,yourList.size());
  • Raedwald
    Raedwald about 6 years
    How is that better than assertEquals?
  • djeikyb
    djeikyb about 6 years
    @Raedwald the output when the assertion fails. i'll try to come back later to edit in the difference. hamcrest matchers can generate detailed failure messages. it's possible for junit to simply overload assertEquals with similar goodness. but mostly junit provides core unit test features, and hamcrest provides a nice-to-have object difference describer library.
  • user1778602
    user1778602 about 6 years
    or with a single line: assertThat(yourList.toArray(), arrayContainingInAnyOrder(1,2,3,4,5));
  • walen
    walen almost 5 years
    "This is not good for perfomance." → I'm not sure to what degree one should take performance into account when writing unit tests... But sure, comparing strings via their toString() version is not the best way.
  • iec2011007
    iec2011007 about 4 years
    will this not fails if the order is not matched ??
  • Prince
    Prince over 3 years
    Much simpler to upgrade to JUnit5. Migration Instructions From: testImplementation("junit:junit:4.13") To: testImplementation("org.junit.jupiter:junit-jupiter-api:5.7.‌​0")
  • CoolMind
    CoolMind over 3 years
    @djeikyb, Assert.assertEquals works right and outputs expected and actual lists when comparison fails.
  • Greg Knox
    Greg Knox almost 3 years
    The order of the parameters in Assert.assertEquals is expected result then the actual result, so in your snippet it should be Assert.assertEquals(expected, actual);