如何在 Mockito 中覆盖 unstubbed void 方法的默认行为?

For*_*ght 2 java junit mockito

我正在模拟一个相当复杂的对象层次结构,在我处理它的过程中,可能涉及到大量的方法。如果我错过了一个非空的方法并保持不变,默认情况下 Mockito 会使其返回 null,这会快速触发 NPE,我很容易找到它。然而,如果我错过了一个 void 方法,默认行为是什么都不做,这经常导致下游的失败并且更难调试。我想更改此默认值,例如抛出自定义异常,但似乎没有找到方法。提前致谢!

Jef*_*ica 5

You can write a default answer, passed in as a parameter to Mockito.mock. Unfortunately, due to limitations of Java annotations, it's not so easy to make this default behavior for @Mock-annotated fields.

public static class ThrowingAnswer implements Answer<Object> {
  @Override public Void answer(InvocationOnMock invocation) throws Throwable {
    if (invocation.getMethod().getReturnType() == Void.TYPE) {
      throw new UnsupportedOperationException(String.format(
          "Method %s not stubbed on %s",
          invocation.getMethod().getName(),
          invocation.getMock()));
    }
    return Answers.RETURNS_DEFAULTS.answer(invocation);
  }
}

YourClass mockYourClass = Mockito.mock(YourClass.class, new ThrowingAnswer());
Run Code Online (Sandbox Code Playgroud)

Though you would be forced to use doAnswer() syntax for void methods anyway, be aware if you change the above to include non-void methods that you will be forced to use doReturn() syntax. This is because when(foo.bar()).thenReturn(baz) relies on the call to foo.bar() within the when() statement, but you will have stubbed it to throw an exception.

Also, if you find it hard to tell which void methods are relevant to stub on an external-enough-to-mock service, it may be a code smell that your service is doing to much, or that your system-under-test's interactions are not defined well enough. If you find yourself in this situation often, it may be time to document, refactor, or both.