How to assertThat superclass list equal to subclass matcher using hamcrest and mockito
Question
I am trying to do the following.
final Matcher<SuperClass> matcher1 = Matchers.hasProperty("a", equalTo("b"));
final Matcher<SuperClass> matcher2 = Matchers.hasProperty("c", equalTo("d"));
final Matcher<SuperClass> matchers = Matchers.allOf(matcher1, matcher2);
List<SubClass> list = someStuff();
assertThat(list, everyItem(matchers));
I am getting a compilation error on the assert line, is there any easy way to get rid of this.
Solution
Option 1:
@SuppressWarnings({"unchecked", "rawtypes"})
@Test public void yourTest() {
final Matcher<SuperClass> matcher1 = Matchers.hasProperty("a", equalTo("b"));
final Matcher<SuperClass> matcher2 = Matchers.hasProperty("c", equalTo("d"));
final Matcher<SuperClass> matchers = Matchers.allOf(matcher1, matcher2);
List<SubClass> list = someStuff();
// Note cast to raw type here, corresponding to the suppressed warnings.
assertThat(list, (Matcher) everyItem(matchers));
}
Option 2:
// These are all of type Matcher<SubClass> instead.
final Matcher<SubClass> matcher1 = Matchers.hasProperty("a", equalTo("b"));
final Matcher<SubClass> matcher2 = Matchers.hasProperty("c", equalTo("d"));
final Matcher<SubClass> matchers = Matchers.allOf(matcher1, matcher2);
List<SubClass> list = someStuff();
assertThat(list, everyItem(matchers));
Why? Java's generics handling is too clever for Hamcrest. everyItem(matchers)
will return a Matcher<Iterable<SuperClass>>
, but you don't have an Iterable<SuperClass>
, you have an Iterable<SubClass>
. It would all be fine if you actually had your Matcher methods produce a Matcher<Iterable<? extends SuperClass>>
, but it's nearly impossible for you to convince Java that your matcher1
and matcher2
are compatible with one another.
OTHER TIPS
Generics.
The problem with your code is that you try to assert that a list with type List<SubClass>
matches every item of a matcher with type Matcher<SuperClass>
.
Even though SuperClass
extends SubClass
, the assertThat
method requires the two to be the same.
So if you can coerce your someStuff()
method to return a list of of SuperClass
, you should be home free. I.e. something like this
List<SuperClass> list = someStuff();
assertThat(list, everyItem(matchers));
would get rid of the compilation error.