Mockito: doAnswer Vs thenReturn

123

Ich verwende Mockito für spätere Unit-Tests. Ich bin verwirrt, wann ich doAnswervs verwenden soll thenReturn.

Kann mir jemand im Detail helfen? Bisher habe ich es mit versucht thenReturn.

Rajkumar Thambu
quelle

Antworten:

166

Sie sollten verwenden thenReturnoder doReturnwenn Sie den Rückgabewert kennen, wenn Sie einen Methodenaufruf verspotten. Dieser definierte Wert wird zurückgegeben, wenn Sie die verspottete Methode aufrufen.

thenReturn(T value) Legt einen Rückgabewert fest, der beim Aufruf der Methode zurückgegeben werden soll.

@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 wird verwendet, wenn Sie zusätzliche Aktionen ausführen müssen, wenn eine verspottete Methode aufgerufen wird, z. B. wenn Sie den Rückgabewert basierend auf den Parametern dieses Methodenaufrufs berechnen müssen.

Verwenden doAnswer()Sie diese Option, wenn Sie eine void-Methode mit generic stubben möchten Answer.

Antwort gibt eine Aktion an, die ausgeführt wird, und einen Rückgabewert, der zurückgegeben wird, wenn Sie mit dem Modell interagieren.

@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");
}
Roland Weisleder
quelle
hi @Roland Weisleder aber manchmal solltest du einen wertgenerierten inneren Code zurückgeben und nichts mit Argumenten zu tun haben, zB code = UUID.randomUUID()fand ich es unmöglich, dies mit zu implementieren mockito.
Zhuguowei
3
Wenn Ihr Mock für jeden Aufruf eine neue UUID zurückgeben soll, implementieren Sie das Answerjust with return UUID.randomUUID();.
Roland Weisleder
Kann ich diese Methode aus der neuen Antwortinitialisierung übernehmen und in eine Methode einfügen, um den Code etwas sauberer zu machen?
Linie
3
@Line Answerist eine funktionale Schnittstelle, sodass Sie sie mit Java 8 durch einen Lambda-Ausdruck ersetzen können. Wenn das nicht sauber genug ist, ist jedes andere übliche und ungewöhnliche Refactoring möglich.
Roland Weisleder
@ zhuguowei: einen wertgenerierten inneren Code zurückgeben? Was meinst du damit?
Saurabh Patil
34

doAnswerund thenReturnmachen Sie dasselbe, wenn:

  1. Sie verwenden Mock, nicht Spy
  2. Die Methode, die Sie stubben, gibt einen Wert zurück, keine void-Methode.

Lassen Sie uns diesen BookService verspotten

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

Sie können getAuthor () mit doAnswerund stubben 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();

Beachten Sie, dass Sie bei Verwendung doAnswerkeine Methode weitergeben können when.

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

Also, wann würden Sie doAnsweranstelle von verwenden thenReturn? Ich kann mir zwei Anwendungsfälle vorstellen:

  1. Wenn Sie die void-Methode "stubben" möchten.

Mit doAnswer können Sie beim Aufrufen der Methode einige zusätzliche Aktionen ausführen. Lösen Sie beispielsweise einen Rückruf für queryBookTitle aus.

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. Wenn Sie Spy anstelle von Mock verwenden

Bei Verwendung von when-thenReturn on Spy ruft Mockito die echte Methode auf und speichert dann Ihre Antwort. Dies kann zu einem Problem führen, wenn Sie keine echte Methode aufrufen möchten, wie in diesem Beispiel:

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

Mit doAnswer können wir es sicher stubben.

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

Wenn Sie beim Aufrufen der Methode keine zusätzlichen Aktionen ausführen möchten, können Sie diese einfach verwenden doReturn.

List list = new LinkedList();
List spy = spy(list);
doReturn("java").when(spy).get(0);
assertEquals("java", spy.get(0));
Aldok
quelle
Was ist, wenn die verspottete Methode nichtig ist?
Igor Donin
1
Igor, genau hier kommt doAnswer () ins Spiel, und das hat er in der obigen Antwort behandelt.
Saurabh Patil
Bei Verwendung doAnswer(new Answer() { ... return null;}erhalte ich in Eclipse eine Warnung für "Antwort ist ein Rohtyp. Verweise auf den generischen Typ Antwort <T> sollten parametrisiert werden". Gibt es eine Möglichkeit, dies zu beheben (außer die Warnung von c zu ignorieren)?
LazR