Подтвердить что ты не робот

Как заставить 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) определен.

4b9b3361

Ответ 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

Надеюсь, что это поможет.