Как заставить Mockito вызывать исключение, когда макет вызывается с неопределенными параметрами?
Можно ли генерировать исключение всякий раз, когда mock вызывается с неопределенными аргументами? Существует Answers.RETURNS_SMART_NULLS
, но это не совсем то, что мне нужно, так как оно не работает, если null
- это законное возвращаемое значение, которое не приводит к NullPointerException
, а скорее к ошибкам позже.
Изменить: некоторый фон. Итак, в Mockito, когда вы определяете макет, вы указываете возвращаемые значения для каждого вызова следующим образом:
when(myMock.someMethod(arg1, arg2)).thenReturn(returnValue);
Когда myMock.someMethod
вызывается с аргументами, для которых я не дал возвращаемого значения в тесте, он просто возвращает null
. Я хотел бы настроить его для сбоя сразу и сказать мне, что я забыл определить возвращаемое значение для некоторой комбинации параметров.
Изменить 2: Были предложения по предоставлению пользовательского defaultAnswer
, который выдавал бы исключения при вызове. К сожалению, это не работает. Метод ответов по умолчанию answer()
вызывается, даже если присутствует макет. Здесь образец:
public class Test {
public static class Adder {
public int add(int a, int b) {
return a + b;
}
}
public static final Answer<Object> THROW_ON_UNDEFINED_ARGS = new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
throw new IllegalArgumentException(
String.format("Calling a mock with undefined arguments: %s %s",
invocation.getMethod(),
Arrays.toString(invocation.getArguments())));
}
};
public static void main(String[] args) {
Adder adderMock = mock(Adder.class, THROW_ON_UNDEFINED_ARGS);
when(adderMock.add(2, 3)).thenReturn(5);
System.out.println(adderMock.add(2, 3));
}
}
Исключение выбрано, даже если adderMock.add(2, 3)
определен.
Ответы
Ответ 1
Вы можете указать по умолчанию Answer
в построении вашего макета, который всегда выдает исключение. Затем каждый вызов, который будет заштрихован, будет действовать, как обычно. Все, что находится за пределами этих путей, выдает исключение. Что-то вроде этого:
final String arg = "some arg";
Collection<Object> object = mock(Collection.class, new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
throw new IllegalArgumentException("You cannot invoke " + invocation.getMethod() +
" with " + Arrays.toString(invocation.getArguments()));
}
});
doReturn(true).when(object).add(arg);
object.add(arg); // Goes ok
object.add("azertyuiop"); // Throws the exception
Ответ 2
Во-первых, немного "хорошей техники" бормотание - зачем вы хотели бы это сделать? Mockito пытается "продвигать" стиль BDD - вы настраиваете (выставляете) свои звонки, вы выполняете код и проверяете взаимодействия в точности так, как вы ожидали, а не "ничего не называли" - пытаетесь ли вы сделать что-то, описанное в Поиск нерелевантного вызова?
Обычно, если я хочу издеваться над всеми случаями, но один - это заставляет меня спросить себя, действительно ли мои тесты в порядке.
В любом случае, к теме:)
В Mockito вы можете определить несколько when
с разными значениями, например
class Foo {
public String bar(int a) {
return "bar = " + a;
}
}
Mockito.when(task.bar(Matchers.anyInt())).thenReturn("L")
Mockito.when(task.bar(3)).thenThrow(new IllegalAccessError())
task.bar(4); // returns "L"
task.bar(3); //throws IllegalAccessError
Обратите внимание, что порядок when
имеет значение. Правила обрабатываются в обратном порядке (или, скорее, переопределяют фактические совпадения).
В моем коде мы сначала издеваемся над anyInt, а затем за 3 - что работает. Если вы отмените его - оба вызова bar()
вернут "L".
Ответ 3
Просто укажите другой способ, которым вы можете это сделать, используя thenAnswer
:
when(myMock.someMethod(anyString(), anyString())).
thenAnswer(new Answer<String>() {
@Override
public String answer(InvocationOnMock invocation) throws Throwable {
Object[] args = invocation.getArguments();
String arg1 = (String) args[0];
String arg2 = (String) args[1];
if ("arg1".equals(arg1) && "arg2".equals(arg2)) return "someValue";
throw new Exception();
}
});
myMock.someMethod("arg1", "arg2"); // Returns "someValue"
myMock.someMethod("xxx", "yyy"); // Throws Exception
Надеюсь, что это поможет.