148

考虑这段代码:

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(). 关于如何处理返回具有有界通配符类型的存根方法的任何指针?

4

5 回答 5

211

为此,您还可以使用非类型安全方法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());
}

正如Mockito 的谷歌小组所讨论的那样

虽然这比 简单thenAnswer,但再次注意它不是类型安全的。如果您担心类型安全,米尔豪斯的回答是正确的。

额外细节

需要明确的是,这是观察到的编译器错误,

The method thenReturn(List<capture#1-of ? extends Number>) in the type OngoingStubbing<List<capture#1-of ? extends Number>> is not applicable for the arguments (List<capture#2-of ? extends Number>)

我相信编译器在when调用期间已经分配了第一个通配符类型,然后无法确认调用中的第二个通配符类型thenReturn是相同的。

看起来thenAnswer没有遇到这个问题,因为它接受通配符类型,而thenReturn接受非通配符类型,必须捕获。来自 Mockito 的OngoingStubbing

OngoingStubbing<T> thenAnswer(Answer<?> answer);
OngoingStubbing<T> thenReturn(T value);
于 2012-05-21T15:52:44.273 回答
34

我假设您希望能够加载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;
}
于 2011-10-05T01:01:31.487 回答
19

我昨天打了同样的事情。@nondescript1 和 @millhouse 的两个答案都帮助我找到了解决方法。我几乎使用了与@millhouse 相同的代码,只是我让它更通用一些,因为我的错误不是由 a 引起的java.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 编译器发出的错误是编译器错误还是代码真的不正确?

于 2013-07-25T19:41:26.697 回答
7

我在这里将fikovnik的评论变成了一个答案,以使其更具可见性,因为我认为这是使用 Java 8+ 的最优雅的解决方案。

Mockito文档doReturn()建议仅作为最后的手段使用(如已接受的答案中所建议的那样)。

相反,为了避免问题中描述的编译器错误,推荐的 Mockitowhen()方法可以与thenAnswer()lambda (而不是辅助方法)一起使用:

Mockito.when(mockedClass.mockedMethod()).thenAnswer(x -> resultList)
于 2019-06-27T12:29:49.153 回答
0

尽管 Marek Radonsky 提出的实用方法有效,但还有一个选项甚至不需要(恕我直言奇怪的)lambda 表达式 fikovnik 建议:

正如对类似问题的回答所示,您还可以使用以下内容

BDDMockito.willReturn(someList).given(dummyClass).dummyMethod();
于 2016-07-13T11:49:35.517 回答