Conflict Overloads for Hamcrest Match

Matches IsIterableContainingInAnyOrder have two overloads for the static factory containsInAnyOrder method (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 doing this as a JUnit test, it passes as expected. It uses the second containsInAnyOrder overload shown above.

Now when I change the statement 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 no longer compiles, because now the compiler prints the return type containsInAnyOrder to

 Matcher<Iterable<? extends List<Matcher<String>>>> 

It seems that the compiler is still picking a second overload. If he used the first, the example should work. Why is he acting like that? How can I do this job?

I am using Hamcrest 1.3 and Oracle Java 1.7.

+6
source share
3 answers

It actually matches overloaded methods. I'm not sure why the first one is chosen, but you can give a hint to choose the right method.

Discarding the Collection argument:

 assertThat(Arrays.asList("foo","bar"), containsInAnyOrder((Collection)Arrays.asList(equalTo("foo"), equalTo("bar")))); 

or specifying the generic type T as <String> (however, do not work with static imports):

 assertThat(Arrays.asList("foo","bar"), IsIterableContainingInAnyOrder.<String>containsInAnyOrder(Arrays.asList(equalTo("foo"), equalTo("bar")))); 
+4
source

This is a little trickier if you map your own objects, rather than simple strings, to get generics. If you use varargs containsInAnyOrder(Matcher<? super T>... itemMatchers) , as in the first example of the question, you will get an Unchecked generics array to warn the varargs parameter. For instance:

 assertThat(myDTOList, containsInAnyOrder(sameStateAs(expectedMyDTO1), sameStateAs(expectedMyDTO2)); 

One way to solve the problem asked by the OP in the question is to define your collection of matches as follows:

 Collection<Matcher<? super MyDTO>> expectedMyDTOs = Arrays.<Matcher<? super MyDTO>>asList(sameStateAs(expectedMyDTO1), sameStateAs(expectedMyDTO2)); // Use like this: assertThat(myDTOList, containsInAnyOrder(expectedMyDTOs); 
+2
source

With hamcrest 1.3, you can use the Matchers class instead of IsIterableContainingInAnyOrder directly, as pointed out by @eee. Matches 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 static imports if you want to Type your call to contain @SuppressWarnings("unchecked") , and this eliminates the need to add @SuppressWarnings("unchecked")

+2
source

Source: https://habr.com/ru/post/953156/


All Articles