如何使 JUnit assertThat() 使用下限通配符?

How to make JUnit assertThat() work with lower bounded wildcard?

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

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

我测试了 classes 实现该接口的方式如下:

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

然后我认为将生产接口更改为:

可能会有所帮助
public List<? extends Action> getActions() {

(允许我 return 子 class 操作列表)。

但是现在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 的 class 更改为

@Override
public List<SomeSubClassOfAction> getActions()

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

Arrays.asList(action1, action2) 会 return 一个 List<Action>is(Arrays.asList(action1, action2)) 因此会 return 一个 Matcher<List<Action>>.

assertThat 具有以下签名:

assertThat(T actual, Matcher<T> matcher)

因此 assertThat 在您的案例中需要以下参数:

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

你的问题是,为什么

@Override
public List<SomeSubClassOfAction> getActions()

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

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

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