Mockito:doAnswer Vs然后返回

Raj*_*mbu 101 java mockito

我正在使用Mockito进行后期单元测试.我很困惑,当使用doAnswerVS thenReturn.

任何人都可以帮我详细吗?到目前为止,我已经尝试过了thenReturn.

Rol*_*der 135

您应该使用thenReturndoReturn在模拟方法调用时知道返回值.调用mocked方法时会返回此定义的值.

thenReturn(T value) 设置调用方法时返回的返回值.

@Test
public void test_return() throws Exception {
    Dummy dummy = mock(Dummy.class);
    int returnValue = 5;

    // choose your preferred way
    when(dummy.stringLength("dummy")).thenReturn(returnValue);
    doReturn(returnValue).when(dummy).stringLength("dummy");
}
Run Code Online (Sandbox Code Playgroud)

Answer 在调用模拟方法时需要执行其他操作时使用,例如,当您需要根据此方法调用的参数计算返回值时.

使用doAnswer()时要与存根通用空隙的方法Answer.

Answer指定执行的操作以及与模拟交互时返回的返回值.

@Test
public void test_answer() throws Exception {
    Dummy dummy = mock(Dummy.class);
    Answer<Integer> answer = new Answer<Integer>() {
        public Integer answer(InvocationOnMock invocation) throws Throwable {
            String string = invocation.getArgumentAt(0, String.class);
            return string.length() * 2;
        }
    };

    // choose your preferred way
    when(dummy.stringLength("dummy")).thenAnswer(answer);
    doAnswer(answer).when(dummy).stringLength("dummy");
}
Run Code Online (Sandbox Code Playgroud)

  • 当您的模拟应该为每次调用返回一个新的 UUID 时,您只需使用 `return UUID.randomUUID();` 来实现 `Answer`。 (3认同)
  • @Line`Answer`是一个功能界面,所以使用Java 8你可以用lambda表达式替换它.如果不够干净,任何其他通常和不寻常的重构都是可能的. (3认同)

ald*_*dok 17

doAnswerthenReturn做同样的事情,如果:

  1. 你正在使用Mock,而不是间谍
  2. 你正在存根的方法是返回一个值,而不是一个void方法.

让我们嘲笑这个BookService

public interface BookService {
    String getAuthor();
    void queryBookTitle(BookServiceCallback callback);
}
Run Code Online (Sandbox Code Playgroud)

您可以使用doAnswer和存根getAuthor()thenReturn.

BookService service = mock(BookService.class);
when(service.getAuthor()).thenReturn("Joshua");
// or..
doAnswer(new Answer() {
    @Override
    public Object answer(InvocationOnMock invocation) throws Throwable {
        return "Joshua";
    }
}).when(service).getAuthor();
Run Code Online (Sandbox Code Playgroud)

请注意,使用时doAnswer,无法传递方法when.

// Will throw UnfinishedStubbingException
doAnswer(invocation -> "Joshua").when(service.getAuthor());
Run Code Online (Sandbox Code Playgroud)

那么,你什么时候用doAnswer而不是thenReturn?我可以想到两个用例:

  1. 当你想要"stub"void方法时.

使用doAnswer,您可以在方法调用时执行一些附加操作.例如,在queryBookTitle上触发回调.

BookServiceCallback callback = new BookServiceCallback() {
    @Override
    public void onSuccess(String bookTitle) {
        assertEquals("Effective Java", bookTitle);
    }
};
doAnswer(new Answer() {
    @Override
    public Object answer(InvocationOnMock invocation) throws Throwable {
        BookServiceCallback callback = (BookServiceCallback) invocation.getArguments()[0];
        callback.onSuccess("Effective Java");
        // return null because queryBookTitle is void
        return null;
    }
}).when(service).queryBookTitle(callback);
service.queryBookTitle(callback);
Run Code Online (Sandbox Code Playgroud)
  1. 当你使用间谍而不是模拟

当使用when-thenReturn on Spy Mockito时会调用真正的方法,然后将你的答案存根.如果您不想调用实际方法,这可能会导致问题,如下例所示:

List list = new LinkedList();
List spy = spy(list);
// Will throw java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
when(spy.get(0)).thenReturn("java");
assertEquals("java", spy.get(0));
Run Code Online (Sandbox Code Playgroud)

使用doAnswer我们可以安全地存根.

List list = new LinkedList();
List spy = spy(list);
doAnswer(invocation -> "java").when(spy).get(0);
assertEquals("java", spy.get(0));
Run Code Online (Sandbox Code Playgroud)

实际上,如果您不想在方法调用时执行其他操作,则可以使用doReturn.

List list = new LinkedList();
List spy = spy(list);
doReturn("java").when(spy).get(0);
assertEquals("java", spy.get(0));
Run Code Online (Sandbox Code Playgroud)


ayo*_*bra 14

最简单的答案是:

\n
    \n
  • 如果您需要方法调用时的固定返回值,那么我们应该使用thenReturn(\xe2\x80\xa6)
  • \n
  • 如果您需要执行某些操作或需要在运行时计算值,那么我们应该使用thenAnswer(\xe2\x80\xa6)
  • \n
\n