Mockito : doAnswer vs thenReturn

2022-08-31 06:55:16

我正在使用Mockito进行服务后期单元测试。我对何时使用vs感到困惑。doAnswerthenReturn

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


答案 1

在模拟方法调用时,应使用 或 当您知道返回值时。调用 mocked 方法时,将返回此定义的值。thenReturndoReturn

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");
}

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

当您要使用泛型 存根 void 方法时使用。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");
}

答案 2

doAnswer并在以下情况下执行相同的操作:thenReturn

  1. 您正在使用模拟,而不是间谍
  2. 您正在存根的方法返回的是值,而不是 void 方法。

让我们来模拟这本书服务

public interface BookService {
    String getAuthor();
    void queryBookTitle(BookServiceCallback callback);
}

您可以使用 和 存根 getAuthor() 。doAnswerthenReturn

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();

请注意,使用 时,不能在 上传递方法。doAnswerwhen

// Will throw UnfinishedStubbingException
doAnswer(invocation -> "Joshua").when(service.getAuthor());

那么,你什么时候会用代替?我可以想到两个用例:doAnswerthenReturn

  1. 当您想要“存根”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);
  1. 当您使用间谍而不是模拟时

当使用当-然后返回间谍莫基托将调用真正的方法,然后存根你的答案。如果您不想调用 real 方法,这可能会导致问题,如以下示例所示:

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));

使用doAnswer,我们可以安全地存根它。

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

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

List list = new LinkedList();
List spy = spy(list);
doReturn("java").when(spy).get(0);
assertEquals("java", spy.get(0));

推荐