Mockito: Методы обрушения, которые возвращают тип с ограниченными дикими картами
Рассмотрим этот код:
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()
. Любые указатели на то, как один идет о методах stubbing, которые возвращают тип с ограниченными wild-cards?
Ответы
Ответ 1
Вы также можете использовать для этого нетипичный безопасный метод 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
, еще раз отметим, что он не является безопасным типом. Если вы беспокоитесь о безопасности типов, ответ 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,
OngoingStubbing<T> thenAnswer(Answer<?> answer);
OngoingStubbing<T> thenReturn(T value);
Ответ 2
Я предполагаю, что вы хотите загрузить 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
Я вчера утром побил то же самое. Оба ответа от @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, является ошибкой компилятора или если код действительно неверен?
Ответ 4
Несмотря на то, что полезный метод, предложенный Мареком Радонским, работает, есть и другой вариант, который даже не требует выражения (ИМХО странно выглядящего) лямбда-выражения fikovnik:
Как этот ответ на аналогичный вопрос, вы также можете использовать следующее:
BDDMockito.willReturn(someList).given(dummyClass).dummyMethod();
Ответ 5
Я превращаю комментарий фиковника в ответ, чтобы сделать его более заметным, так как считаю его наиболее элегантным решением с использованием Java 8+.
Документация Mockito рекомендует использовать doReturn()
(как предложено в принятом ответе) только в качестве крайней меры.
Вместо этого, чтобы обойти ошибку компилятора, описанную в этом вопросе, рекомендуемый подход Mockito when()
может быть использован с thenAnswer()
и лямбда- thenAnswer()
(вместо вспомогательного метода):
Mockito.when(mockedClass.mockedMethod()).thenAnswer(x -> resultList)