This 2013 post on SO asked how to use Hamcrest matchers to verify lists/collections invocations in Mockito. The accepted solution was to cast the Matcher to a (Collection).
I'm trying to do something similar, but running into a class cast error. I am not sure if I am misusing Hamcrest matchers, or if this usage simply isn't supported by Mockito. In my case, I'm trying to use a list of Matchers as my argument:
static class Collaborator
{
void doSomething(Iterable<String> values) {}
}
@Test
public void usingMockito()
{
Collaborator mock = Mockito.mock(Collaborator.class);
mock.doSomething(Arrays.asList("a", "b"));
// legal cast
Mockito.verify(mock).doSomething((Collection<String>)argThat(Matchers.contains("a", "b")));
// legal cast
Mockito.verify(mock).doSomething((Collection<String>)argThat(Matchers.contains(Matchers.equalTo("a"), Matchers.equalTo("b"))));
// illegal cast!!! Cannot cast from Iterable<capture#3-of ? extends List<Matcher<String>>> to Collection<String>
Mockito.verify(mock).doSomething((Collection<String>)argThat(Matchers.contains(Arrays.asList(Matchers.equalTo("a"), Matchers.equalTo("b")))));
}
But I get the cast error:
Cannot cast from Iterable<capture#3-of ? extends List<Matcher<String>>> to Collection<String>
Am I doing something unsupported?
As Jeff Bowman has already pointed out, the problem is that the compiler doesn't know which of the 4 contains
methods you are trying to call.
The list you are constructing
Arrays.asList(Matchers.equalTo("a"), Matchers.equalTo("b"))
is of type
List<Matcher<String>>
but the contains
method you want to call (<E> Matcher<Iterable<? extends E>> contains(List<Matcher<? super E>> itemMatchers)
) expects a type
List<Matcher<? super String>>
as parameter. As your list type doesn't match the expected one, the compiler actually thinks that you are trying to call
<E> Matcher<Iterable<? extends E>> contains(E... items)
The solution: give the compiler what it wants. Create a List<Matcher<? super String>>
instead of a List<Matcher<String>>
:
List<Matcher<? super String>> matchersList = new ArrayList<>();
matchersList.add(Matchers.equalTo("a"));
matchersList.add(Matchers.equalTo("b"));
// no illegal cast anymore
Mockito.verify(mock).doSomething(
(Collection<String>) argThat(Matchers.contains(matchersList)));
EDIT:
Adding Jeff Bowman's inline solution from his comment, that enables the use of Arrays.asList
as stated in the question:
Mockito.verify(mock).doSomething(
(Collection<String>) argThat(
Matchers.contains(
Arrays.<Matcher<? super String>> asList(
Matchers.equalTo("a"), Matchers.equalTo("b")
)
)
)
);