I am using Mockito for service later unit testing. I am confused when to use doAnswer vs thenReturn.
Can anyone help me in detail? So far, I have tried it with thenReturn.
3 Answers
You should use thenReturn or doReturn when you know the return value at the time you mock a method call. This defined value is returned when you invoke the mocked method.
thenReturn(T value)Sets a return value to be returned when the method is called.
@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 is used when you need to do additional actions when a mocked method is invoked, e.g. when you need to compute the return value based on the parameters of this method call.
Use
doAnswer()when you want to stub a void method with genericAnswer.Answer specifies an action that is executed and a return value that is returned when you interact with the mock.
@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"); } 5doAnswer and thenReturn do the same thing if:
- You are using Mock, not Spy
- The method you're stubbing is returning a value, not a void method.
Let's mock this BookService
public interface BookService { String getAuthor(); void queryBookTitle(BookServiceCallback callback); } You can stub getAuthor() using doAnswer and 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(); Note that when using doAnswer, you can't pass a method on when.
// Will throw UnfinishedStubbingException doAnswer(invocation -> "Joshua").when(service.getAuthor()); So, when would you use doAnswer instead of thenReturn? I can think of two use cases:
- When you want to "stub" void method.
Using doAnswer you can do some additionals actions upon method invocation. For example, trigger a callback on 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); - When you are using Spy instead of Mock
When using when-thenReturn on Spy Mockito will call real method and then stub your answer. This can cause a problem if you don't want to call real method, like in this sample:
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)); Using doAnswer we can stub it safely.
List list = new LinkedList(); List spy = spy(list); doAnswer(invocation -> "java").when(spy).get(0); assertEquals("java", spy.get(0)); Actually, if you don't want to do additional actions upon method invocation, you can just use doReturn.
List list = new LinkedList(); List spy = spy(list); doReturn("java").when(spy).get(0); assertEquals("java", spy.get(0)); 3The simplest answer is:
- If you need a fixed return value on method call then we should use thenReturn(…)
- If you need to perform some operation or the value need to be computed at run time then we should use thenAnswer(…)