问题
考虑以下代码:
public class DummyClass {
public List<? extends Number> dummyMethod() {
return new ArrayList<Integer>();
}
}
public class DummyClassTest {
public void testMockitoWithGenerics() {
DummyClass dummyClass = Mockito.mock(DummyClass.class);
List<? extends Number> someList = new ArrayList<Integer>();
Mockito.when(dummyClass.dummyMethod()).thenReturn(someList); //Compiler complains about this
}
}
编译器抱怨正在尝试存根dummyMethod()
的行为。关于如何使用有界通配符返回类型的存根方法的任何指针?
#1 热门回答(132 赞)
为此,你也可以使用非类型安全方法doReturn,
@Test
public void testMockitoWithGenerics()
{
DummyClass dummyClass = Mockito.mock(DummyClass.class);
List<? extends Number> someList = new ArrayList<Integer>();
Mockito.doReturn(someList).when(dummyClass).dummyMethod();
Assert.assertEquals(someList, dummyClass.dummyMethod());
}
asdiscussed在Mockito的谷歌小组。
虽然这比thenAnswer
更简单,但再次注意它不是类型安全的。如果你担心类型安全,millhouse'sanswer是正确的。
额外细节
要清楚,这是观察到的编译器错误,
然后返回类型OngoingStubbing <List <capture#1-of?中的方法返回(List <capture#1-of?extends Number>)? extends Number >>不适用于参数(List <capture#2-of?extends Number>)
我相信编译器在when
call期间分配了第一个通配符类型,然后无法确认thenReturn
call中的第二个通配符类型是否相同。
看起来像thenAnswer
没有遇到这个问题,因为它接受通配符类型而thenReturn
获取必须捕获的非通配符类型。来自Mockito'sOngoingStubbing,
OngoingStubbing<T> thenAnswer(Answer<?> answer);
OngoingStubbing<T> thenReturn(T value);
#2 热门回答(28 赞)
我假设你希望能够使用某些已知值加载someList
;这是一种方法,它使用Answer<T>
一起使用模板化辅助方法来保证所有类型安全:
@Test
public void testMockitoWithGenericsUsingAnswer()
{
DummyClass dummyClass = Mockito.mock(DummyClass.class);
Answer<List<Integer>> answer = setupDummyListAnswer(77, 88, 99);
Mockito.when(dummyClass.dummyMethod()).thenAnswer(answer);
...
}
private <N extends Number> Answer<List<N>> setupDummyListAnswer(N... values) {
final List<N> someList = new ArrayList<N>();
someList.addAll(Arrays.asList(values));
Answer<List<N>> answer = new Answer<List<N>>() {
public List<N> answer(InvocationOnMock invocation) throws Throwable {
return someList;
}
};
return answer;
}
#3 热门回答(11 赞)
我昨天打了同样的话。 @ nondescript1和@millhouse的答案都帮助我找到了解决方法。我几乎使用了与@millhouse相同的代码,除了我使它稍微更通用,因为我的错误不是由ajava.util.List
引起的,而是com.google.common.base.Optional
。因此,我的小助手方法适用于任何类型T
而不仅仅是List<T>
:
public static <T> Answer<T> createAnswer(final T value) {
Answer<T> dummy = new Answer<T>() {
@Override
public T answer(InvocationOnMock invocation) throws Throwable {
return value;
}
};
return dummy;
}
使用这个帮助器方法,你可以写:
Mockito.when(dummyClass.dummyMethod()).thenAnswer(createAnswer(someList));
这编译得很好,并且与thenReturn(...)
方法做同样的事情。
有人知道Java编译器发出的错误是编译器错误还是代码真的不正确?