The matcher IsIterableContainingInAnyOrder
has two overloads for the static factory method containsInAnyOrder
(both have the return type Matcher<java.lang.Iterable<? extends T>>
):
containsInAnyOrder(java.util.Collection<Matcher<? super T>> itemMatchers)
containsInAnyOrder(Matcher<? super T>... itemMatchers)
Now consider the following program:
import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertThat;
import java.util.Arrays;
import org.junit.Test;
public class SomeTest {
@SuppressWarnings("unchecked")
@Test
public void foo() {
assertThat(Arrays.asList("foo","bar"),
containsInAnyOrder(equalTo("foo"), equalTo("bar")));
}
}
When executing this as a JUnit test, it passes, as expected. It uses the second overload of containsInAnyOrder
shown above.
Now, when I change the assertion to this (which exactly matches the example given in the documentation of the first overload):
assertThat(Arrays.asList("foo","bar"),
containsInAnyOrder(Arrays.asList(equalTo("foo"), equalTo("bar"))));
^^^^^^^^^^^^^^
it doesn't compile anymore, because now the compiler infers the return type of containsInAnyOrder
to be
Matcher<Iterable<? extends List<Matcher<String>>>>
It seems like the compiler still chooses the second overload. If it used the first one, the example should work. Why does it behave like this? How can I make this work?
I am using Hamcrest 1.3 and Oracle Java 1.7.
It actually matches both overloaded methods. I'm not sure why exactly the first one is chosen, but you can provide a hint to make it choose the correct method.
By casting the argument to Collection
:
assertThat(Arrays.asList("foo","bar"),
containsInAnyOrder((Collection)Arrays.asList(equalTo("foo"), equalTo("bar"))));
or by specifying the generic type T as <String>
(don't work with static import, though):
assertThat(Arrays.asList("foo","bar"),
IsIterableContainingInAnyOrder.<String>containsInAnyOrder(Arrays.asList(equalTo("foo"), equalTo("bar"))));
This is even a bit harder when you are matching your own objects, rather than simple strings, to get the generics to work out. If you are using the varargs containsInAnyOrder(Matcher<? super T>... itemMatchers)
as in the question's first example you will get a Unchecked generics array creation for varargs parameter warning. For example:
assertThat(myDTOList,
containsInAnyOrder(sameStateAs(expectedMyDTO1), sameStateAs(expectedMyDTO2));
One way to then solve the problem the OP stated in the question, is to define your collection of matchers as follows:
Collection<Matcher<? super MyDTO>> expectedMyDTOs =
Arrays.<Matcher<? super MyDTO>>asList(sameStateAs(expectedMyDTO1), sameStateAs(expectedMyDTO2));
// Use like this:
assertThat(myDTOList,
containsInAnyOrder(expectedMyDTOs);
With hamcrest 1.3 you are able to use the Matchers
class instead of IsIterableContainingInAnyOrder
directly as mentioned by @eee. Matchers actually just calls IsIterableContainingInAnyOrder for you.
import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertThat;
import org.hamcrest.Matchers;
import java.util.Arrays;
import org.junit.Test;
public class SomeTest
{
@Test
public void foo() {
assertThat(Arrays.asList("foo","bar"),
Matchers.<OrderValidationStep>containsInAnyOrder("foo", "bar"));
}
}
Note that you cannot use a static import if you want to Type
your call to containsInAnyOrder, and this removes the need to add @SuppressWarnings("unchecked")
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With