Mockito: методы-заглушки, которые возвращают тип с ограниченными символами - PullRequest
107 голосов
/ 09 сентября 2011

Рассмотрим этот код:

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(). Какие-нибудь указатели на то, как можно использовать методы-заглушки, возвращающие тип с ограниченными символами подстановки?

Ответы [ 5 ]

155 голосов
/ 21 мая 2012

Вы также можете использовать для этого нетипичный безопасный метод 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());
}

как обсуждено в группе Google Mockito.

Хотя это проще, чем thenAnswer, еще раз обратите внимание, что это небезопасно. Если вы беспокоитесь о безопасности типов, ответ на Millhouse правильный.

Дополнительные детали

Для ясности, вот наблюдаемая ошибка компилятора,

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<T> thenAnswer(Answer<?> answer);
OngoingStubbing<T> thenReturn(T value);
29 голосов
/ 05 октября 2011

Я предполагаю, что вы хотите загрузить 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;
}
14 голосов
/ 25 июля 2013

Я вчера ударил то же самое. Оба ответа от @ nondescript1 и @millhouse помогли мне найти обходной путь. Я в значительной степени использовал тот же код, что и @millhouse, за исключением того, что я сделал его несколько более общим, потому что моя ошибка была вызвана не 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, ошибкой компилятора или код действительно неверный?

1 голос
/ 27 июня 2019

Я превращаю комментарий 1002 * fikovnik в ответ, чтобы сделать его более заметным, так как я считаю, что это наиболее элегантное решение с использованием Java 8 +.

В документации Mockito рекомендуется использовать doReturn() (как предлагается в принятом ответе) только в качестве крайней меры.

Вместо этого, чтобы обойти ошибку компилятора, описанную в этом вопросе, рекомендуемый подход Mockito when() может использоваться с thenAnswer() и лямбда-выражением (вместо вспомогательного метода):

Mockito.when(mockedClass.mockedMethod()).thenAnswer(x -> resultList)
0 голосов
/ 13 июля 2016

Хотя полезный метод, предложенный Мареком Радонским, работает, есть и другой вариант, который даже не требует (ИМХО странно выглядящего) лямбда-выражения, предложенного fikovnik:

Как показывает этот ответ на похожий вопрос, вы также можете использовать следующее:

BDDMockito.willReturn(someList).given(dummyClass).dummyMethod();
...