initially, I had this piece of production code:
interface ActionSequence {
public List<Actions> getActions();
I tested classes implementing that interface with something like this:
assertThat(sequenceUnderTest.getActions(), is(Arrays.asList(action1, action2));
Then I figured that it might be beneficial to change the production interface to:
public List<? extends Action> getActions() {
(to allow me to return lists of subclasses of Action).
But now eclipse tells me:
The method assertThat(T, Matcher<? super T>) in the type Assert is not applicable for the arguments (List<capture#1-of ? extends Action>, Matcher<List<Action>>)
I figured: when I change the class that implements ActionInterface to do
@Override
public List<SomeSubClassOfAction> getActions()
(instead of keeping the wildcard) ... then everything works. But why?
Arrays.asList(action1, action2)
will return a List<Action>
.
is(Arrays.asList(action1, action2))
will therefore return a Matcher<List<Action>>
.
assertThat has the following signature:
assertThat(T actual, Matcher<T> matcher)
So assertThat requires the following parameters in your case:
assertThat(List<Action>, Matcher<List<Action>>)
But your first parameter is a List<? extends Action>
And a List<Action>
is completely different from a List<? extends Action>
.
For example, you cannot put Action elements into a List<SomeSubClassOfAction>
.
This is why this won't work.
For details, see Angelika Langer's excellent site: http://www.angelikalanger.com/GenericsFAQ/FAQSections/Index.html