如何在使用未定义的参数调用模拟时使Mockito抛出异常?

时间:2015-04-09 10:48:12

标签: java mockito

是否可以在使用非预定义参数调用模拟时抛出异常?有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),也会抛出异常。

3 个答案:

答案 0 :(得分:8)

你可以在模拟的构造中提供一个默认的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

答案 1 :(得分:3)

首先,有点“好工程”嘟?? - 你为什么要这样做? Mockito试图'推广'BDD风格 - 你设置(模拟)你的调用,你执行代码并验证交互完全符合你的预期,而不是'它没有调用任何其他' - 你试图做一些描述的东西Finding irrelevant invocation? 一般来说,如果我想模仿所有案例,只需要一个 - 这让我自问我的测试是否真的很好。

无论如何,关于主题:)

在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'。

答案 2 :(得分:1)

只需指出另一种方法,即使用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

希望它有所帮助。