Mockito ArgumentMatchers

Mockito ArgumentMatchers

1. Überblick

Dieses Tutorial zeigthow to use the ArgumentMatcher and how it differs from the ArgumentCaptor.

Eine Einführung in das Mockito-Framework finden Sie unterto this article.

2. Maven-Abhängigkeiten

Wir müssen ein einzelnes Artefakt hinzufügen:


    org.mockito
    mockito-core
    2.21.0
    test

Die neueste Version vonMockito finden Sie aufMaven Central.

3. ArgumentMatchers

Das Konfigurieren einer verspotteten Methode auf verschiedene Arten ist möglich. Eine davon ist, feste Werte zurückzugeben:

doReturn("Flower").when(flowerService).analyze("poppy");

Im obigen Beispiel wird die "Blume" vonStringnur zurückgegeben, wenn der Analysedienst die "Mohnblume" vonStringerhält.

Abermaybe we need to respond to a wider range of values or beforehand unknown values.

In all diesen Szenarienwe can configure our mocked methods with argument*matchers*:

when(flowerService.analyze(anyString())).thenReturn("Flower");

Aufgrund des Argument-Matchers vonanyStringist das Ergebnis das gleiche, unabhängig davon, welchen Wert wir für die Analyse übergeben. ArgumentMatchers ermöglicht uns eine flexible Überprüfung oder Stubbing.

Wenn eine Methode mehr als ein Argument hat,it isn’t possible to use ArgumentMatchers for only some of the arguments. Mockito erfordert, dass Sie alle Argumente entweder nachmatchers oder nach exakten Werten angeben.

Ein nächstes Beispiel ist ein falscher Ansatz:

abstract class FlowerService {
    public abstract boolean isABigFlower(String name, int petals);
}

FlowerService mock = mock(FlowerService.class);

when(mock.isABigFlower("poppy", anyInt())).thenReturn(true);

Um das Problem zu beheben und den Namen desString"poppy" wie gewünscht beizubehalten, verwenden wireq matcher:

when(mock.isABigFlower(eq("poppy"), anyInt())).thenReturn(true);

Es gibt zwei weitere Punkte, die zu beachten sind, wennmatchers verwendet werden:

  • We can’t use them as a return value, ein genauer Wert ist erforderlich, wenn Anrufe gestoppt werden

  • Schließlichwe can’t use argument matchers outside of verification or stubbing

Im letzten Fall erkenntMockito das falsch platzierte Argument und wirft einInvalidUseOfMatchersException.

Ein schlechtes Beispiel könnte sein:

String orMatcher = or(eq("poppy"), endsWith("y"));
verify(mock).analyze(orMatcher);

Der oben beschriebene Code kann folgendermaßen implementiert werden:

verify(mock).analyze(or(eq("poppy"), endsWith("y")));

Mockito bietet auchAdditionalMatchers zum Implementieren allgemeiner logischer Operationen ("nicht", "und", "oder") fürArgumentMatchers, die sowohl primitiven als auch nicht primitiven Typen entsprechen:

verify(mock).analyze(or(eq("poppy"), endsWith("y")));

4. Benutzerdefinierter Argumentvergleich

Erstellen vonour matcher can be good to select the best possible approach for a given scenario and produce highest quality test, das sauber und wartbar ist.

Zum Beispiel könnten wir einMessageController haben, das Nachrichten liefert. Es erhält einMessageDTO und daraus wird einMessage erstellt, das vonMessageService geliefert wird.

Unsere Überprüfung wird einfach sein. Stellen Sie sicher, dass wirMessageService genau 1 Mal mitany Message: aufgerufen haben

verify(messageService, times(1)).deliverMessage(any(Message.class));

Aufgrund vonthe Message is constructed inside the method under test müssen wirany alsmatcher verwenden.

Mit diesem Ansatz können wir die Daten innerhalb derMessage,which can be different compared to the data inside MessageDTO nicht validieren.

Aus diesem Grund werden wir einen benutzerdefinierten Argument-Matcher implementieren:

public class MessageMatcher implements ArgumentMatcher {

    private Message left;

    // constructors

    @Override
    public boolean matches(Message right) {
        return left.getFrom().equals(right.getFrom()) &&
          left.getTo().equals(right.getTo()) &&
          left.getText().equals(right.getText()) &&
          right.getDate() != null &&
          right.getId() != null;
    }
}

To use our matcher, we need to modify our test and replace any by argThat:

verify(messageService, times(1)).deliverMessage(argThat(new MessageMatcher(message)));

Jetzt wissen wir, dass die Instanz vonMessagedieselben Daten wie unsere Instanz vonMessageDTOhat.

5. Custom Argument Matcher vs. ArgumentCaptor

Beide Technikencustom argument matchers undArgumentCaptor können verwendet werden, um sicherzustellen, dass bestimmte Argumente an Mocks übergeben wurden.

ArgumentCaptor may be a better fit if we need it to assert on argument values, um die Überprüfung abzuschließenor our custom argument matcher is not likely to be reused.

Custom argument matchers überArgumentMatcher eignen sich normalerweise besser zum Stubben.

6. Fazit

In diesem Artikel haben wir ein Merkmal vonMockito, ArgumentMatcher und dessen Differenz zuArgumentCaptor. untersucht

Wie immer ist der vollständige Quellcode der Beispieleover on GitHub verfügbar.