189

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.

tkruse
  • 10,222
  • 7
  • 53
  • 80
Rajkumar Thambu
  • 2,061
  • 2
  • 15
  • 7

3 Answers3

237

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 generic Answer.

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");
}
mkobit
  • 43,979
  • 12
  • 156
  • 150
Roland Weisleder
  • 9,668
  • 7
  • 37
  • 59
  • hi @Roland Weisleder but sometimes you should return some value generated inner code and nothing to do with arguments, e.g. `code = UUID.randomUUID()`, I found impossible to implement this with `mockito`. – zhuguowei Sep 05 '16 at 03:02
  • 4
    When your mock should return a new UUID for each invocation you would implement the `Answer` just with `return UUID.randomUUID();`. – Roland Weisleder Sep 05 '16 at 09:07
  • Can I take this method from new Answer initialization ant put it in some method, to make the code a little more cleaner? – Line May 23 '17 at 10:24
  • 3
    @Line `Answer` is a functional interface, so with Java 8 you could replace it with a lambda expression. If the isn't clean enough any other usual and unusual refactoring is possible. – Roland Weisleder May 28 '17 at 16:17
  • @ zhuguowei: return some value generated inner code? What do you mean by that? – Saurabh Patil Nov 30 '18 at 04:50
59

doAnswer and thenReturn do the same thing if:

  1. You are using Mock, not Spy
  2. 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:

  1. 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);
  1. 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));
aldok
  • 17,295
  • 5
  • 53
  • 64
  • what if the mocked method is void? – Igor Donin Oct 04 '18 at 16:47
  • 1
    Igor, that's exactly where doAnswer() comes into picture and he has covered that in the answer above. – Saurabh Patil Nov 30 '18 at 04:46
  • When using `doAnswer(new Answer() { ... return null;}` i get a warning in eclipse for "Answer is a raw type. References to generic type Answer should be parameterized". Is there a way to resolve this (except ignoring the warning ofc)? – LazR Feb 28 '19 at 10:51
  • 1
    Note that when using doAnswer, you can't pass a method on when --> this line saved me, thanks – mnagdev Mar 31 '23 at 09:13
14

The 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(…)
Ayoub Boumzebra
  • 3,885
  • 3
  • 21
  • 37