Mockito : doAnswer Vs thenReturn

前端 未结 2 1105
礼貌的吻别
礼貌的吻别 2020-12-04 07:38

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,

相关标签:
2条回答
  • 2020-12-04 07:43

    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));
    
    0 讨论(0)
  • 2020-12-04 07:50

    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");
    }
    
    0 讨论(0)
提交回复
热议问题