如何使JUnit assertThat()与较低的有界通配符一起工作?

时间:2016-01-15 12:57:41

标签: java generics junit assertthat

最初,我有这段生产代码:

interface ActionSequence {
   public List<Actions> getActions();

我测试了实现该接口的类,如下所示:

assertThat(sequenceUnderTest.getActions(), is(Arrays.asList(action1, action2));

然后我认为将生产界面更改为:

可能是有益的
public List<? extends Action> getActions() {

(允许我返回Action的子类列表)。

但是现在eclipse告诉我:

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>>)

我想:当我更改实现ActionInterface的

@Override
public List<SomeSubClassOfAction> getActions()

(而不是保留通配符)...然后一切正常。但为什么呢?

2 个答案:

答案 0 :(得分:2)

Arrays.asList(action1, action2)将返回List<Action>。 因此,is(Arrays.asList(action1, action2))将返回Matcher<List<Action>>

断言具有以下签名:

assertThat(T actual, Matcher<T> matcher)

所以断言在你的情况下需要以下参数:

assertThat(List<Action>, Matcher<List<Action>>)

但你的第一个参数是List<? extends Action> List<Action>List<? extends Action>完全不同。 例如,您不能将Action元素放入List<SomeSubClassOfAction>。 这就是为什么这不起作用的原因。

有关详细信息,请参阅Angelika Langer的优秀网站:http://www.angelikalanger.com/GenericsFAQ/FAQSections/Index.html

答案 1 :(得分:1)

你的问题是,为什么

@Override
public List<SomeSubClassOfAction> getActions()

的合法实施
public List<? extends Action> getActions()

答案是协变回报。由于允许Java1.5子类专门化返回继承的方法。

但我不建议在返回参数中使用通配符类型,因为它不是客户端友好的。请参阅Generic wildcard types should not be used in return parameters及其来自 Effective Java

的引用