Hamcrest compare collections
Asked Answered
N

7

150

I'm trying to compare 2 lists:

assertThat(actual.getList(), is(Matchers.containsInAnyOrder(expectedList)));

But idea

java: no suitable method found for assertThat(java.util.List<Agent>,org.hamcrest.Matcher<java.lang.Iterable<? extends model.Agents>>)
method org.junit.Assert.<T>assertThat(T,org.hamcrest.Matcher<T>) is not applicable
  (no instance(s) of type variable(s) T exist so that argument type org.hamcrest.Matcher<java.lang.Iterable<? extends model.Agents>> conforms to formal parameter type org.hamcrest.Matcher<T>)
method org.junit.Assert.<T>assertThat(java.lang.String,T,org.hamcrest.Matcher<T>) is not applicable
  (cannot instantiate from arguments because actual and formal argument lists differ in length)

How should I write it?

Nationality answered 7/2, 2014 at 10:0 Comment(0)
G
204

If you want to assert that the two lists are identical, don't complicate things with Hamcrest:

assertEquals(expectedList, actual.getList());

If you really intend to perform an order-insensitive comparison, you can call the containsInAnyOrder varargs method and provide values directly:

assertThat(actual.getList(), containsInAnyOrder("item1", "item2"));

(Assuming that your list is of String, rather than Agent, for this example.)

If you really want to call that same method with the contents of a List:

assertThat(actual.getList(), containsInAnyOrder(expectedList.toArray(new String[expectedList.size()]));

Without this, you're calling the method with a single argument and creating a Matcher that expects to match an Iterable where each element is a List. This can't be used to match a List.

That is, you can't match a List<Agent> with a Matcher<Iterable<List<Agent>>, which is what your code is attempting.

Gapin answered 7/2, 2014 at 13:21 Comment(6)
+1 for the "If you really want to call that same method with the contents of a List". Sadly I couldn't get that solved myself. Specially that there is a constructor that takes in a collection.Train
@Tim Not quite; containsInAnyOrder requires that all elements are present, so that first assertion will fail. See hasItems if you want to check that at least those elements are present.Gapin
If you use containsInAnyOrder, you should first make sure both lists have the same size... If actual.getList() happens to contain "item1", "item3", "item2", the test will pass and maybe you want to make sure it only contains the items listed... In that case you could use assertThat(actual.getList().size(), equalTo(2)); before the containsInAnyOrder, this way you make sure both lists have the same contents.Crenation
@Crenation you're thinking of hasItems. The extra check is unnecessary here. See the comment to Tim above, and also How do Hamcrest's hasItems, contains and containsInAnyOrder differ?Gapin
Kotlin users: don't forget to add the spread operator (*expectedList.toTypedArray()) when passing an array as varargs!Anking
Can I draw your attention to #68108241 I tried the above and was dealing with a significantly more complex list of items to match - the answer here resolved me issueLizarraga
W
83
List<Long> actual = Arrays.asList(1L, 2L);
List<Long> expected = Arrays.asList(2L, 1L);
assertThat(actual, containsInAnyOrder(expected.toArray()));

Shorter version of @Joe's answer without redundant parameters.

Whish answered 1/3, 2015 at 3:25 Comment(0)
T
50

To complement @Joe's answer:

Hamcrest provides you with four main methods to match a list:

contains Checks for matching all the elements considering the order. If the list has more or fewer elements, it will fail

containsInAnyOrder Checks for matching all the elements, and it doesn't matter the order. If the list has more or fewer elements, will fail

hasItems Checks just for the specified objects it doesn't matter if the list has more

hasItem Checks just for one object it doesn't matter if the list has more

All of them can receive a list of objects and use the equals method for comparison or can be mixed with other matchers like @borjab mentioned:

assertThat(myList , contains(allOf(hasProperty("id", is(7L)), 
                                   hasProperty("name", is("testName1")),
                                   hasProperty("description", is("testDesc1"))),
                             allOf(hasProperty("id", is(11L)), 
                                   hasProperty("name", is("testName2")),
                                   hasProperty("description", is("testDesc2")))));

http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html#contains(E...) http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html#containsInAnyOrder(java.util.Collection) http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html#hasItems(T...)

Thaumatology answered 17/5, 2017 at 16:40 Comment(2)
Great decision in case list items are not of primitive type.Interstellar
Is there a type safe way of doing this?Kibitz
T
21

With existing Hamcrest libraries (as of v.2.0.0.0) you are forced to use Collection.toArray() method on your Collection in order to use containsInAnyOrder Matcher. Far nicer would be to add this as a separate method to org.hamcrest.Matchers:

public static <T> org.hamcrest.Matcher<java.lang.Iterable<? extends T>> containsInAnyOrder(Collection<T> items) {
    return org.hamcrest.collection.IsIterableContainingInAnyOrder.<T>containsInAnyOrder((T[]) items.toArray());
}

Actually I ended up adding this method to my custom test library and use it to increase readability of my test cases (due to less verbosity).

Telephoto answered 8/7, 2016 at 8:57 Comment(1)
Nice one, I will use this helper. The assert message here is more informative: it names the missing items one-by-one, not just: the list should be elem1, elem2, .. elem99, but I got elem1, elem2, ..., elem98 -- good luck finding the missing one.Personification
O
5

For list of objects you may need something like this:

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.beans.HasPropertyWithValue.hasProperty;
import static org.hamcrest.Matchers.is;

@Test
@SuppressWarnings("unchecked")
public void test_returnsList(){

    arrange();
  
    List<MyBean> myList = act();
    
    assertThat(myList , contains(allOf(hasProperty("id",          is(7L)), 
                                       hasProperty("name",        is("testName1")),
                                       hasProperty("description", is("testDesc1"))),
                                 allOf(hasProperty("id",          is(11L)), 
                                       hasProperty("name",        is("testName2")),
                                       hasProperty("description", is("testDesc2")))));
}

Use containsInAnyOrder if you do not want to check the order of the objects.

P.S. Any help to avoid the warning that is suppresed will be really appreciated.

Ownership answered 9/3, 2016 at 19:0 Comment(0)
P
4

Make sure that the Objects in your list have equals() defined on them. Then

assertThat(generatedList, is(equalTo(expectedList)));

works.

Physiography answered 12/10, 2017 at 16:47 Comment(0)
U
-6

To compare two lists with the order preserved (strict order) use.

assertThat(actualList, contains("item1","item2"));

If we want to compare without a specific order we can use below command

assertThat(collection, containsInAnyOrder("item1","item2"));
Unscreened answered 11/11, 2015 at 17:28 Comment(6)
This does not answer the question.Ryanryann
It partially does.Thaumatology
@Thaumatology What do you mean? Why do you say that? The result of the method is right in my environment.Tautomerism
@Tautomerism The code is checking that the actualList contains the elements inside of contains matcher, that will fail if the elements are not in the same order and will fail too if it contains more elements or is missing one.Thaumatology
@Thaumatology so the purpose of the code is to examine the exact equality(same lengths, values and order) in two lists, right?Tautomerism
@Tautomerism right, I added some other hamcrest methods in a separate answer for when you want to compare other aspects of a list and its contentsThaumatology

© 2022 - 2024 — McMap. All rights reserved.