Mockito ArgumentMatchers

1. Übersicht

Dieses Tutorial zeigt, wie der ArgumentMatcher verwendet wird und wie er sich vom ArgumentCaptor unterscheidet .

Eine Einführung in das Mockito-Framework finden Sie in diesem Artikel.

2. Maven-Abhängigkeiten

Wir müssen ein einzelnes Artefakt hinzufügen:

 org.mockito mockito-core 2.21.0 test 

Die neueste Version von Mockito finden Sie auf Maven Central .

3. ArgumentMatchers

Das Konfigurieren einer verspotteten Methode auf verschiedene Arten ist möglich. Eine davon ist die Rückgabe fester Werte:

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

Im obigen Beispiel wird der String "Flower" nur zurückgegeben, wenn der Analysedienst den String "poppy" erhält .

Aber vielleicht müssen wir auf einen größeren Wertebereich oder auf unbekannte Werte reagieren .

In all diesen Szenarien können wir unsere verspotteten Methoden mit Argument- Matchern konfigurieren :

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

Aufgrund des anyString- Argumentvergleichs ist das Ergebnis nun 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 enthält, können ArgumentMatchers nicht nur für einige der Argumente verwendet werden . Bei Mockito müssen Sie alle Argumente entweder nach Matchern oder nach genauen 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 String- Namen "poppy" wie gewünscht beizubehalten , verwenden wir eq matcher :

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

Bei der Verwendung von Matchern sind zwei weitere Punkte zu beachten :

  • Wir können sie nicht als Rückgabewert verwenden. Beim Stubben von Aufrufen ist ein genauer Wert erforderlich
  • Schließlich können wir keine Argument- Matcher außerhalb der Überprüfung oder des Stubbens verwenden

Im letzten Fall erkennt Mockito das falsch platzierte Argument und löst eine InvalidUseOfMatchersException aus .

Ein schlechtes Beispiel könnte sein:

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

Der Weg, um den obigen Code zu implementieren, ist:

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

Mockito bietet außerdem AdditionalMatchers , um allgemeine logische Operationen ('not', 'und', 'oder') auf ArgumentMatchers zu implementieren , die sowohl primitiven als auch nicht primitiven Typen entsprechen:

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

4. Benutzerdefinierter Argument-Matcher

Das Erstellen unseres Matchers kann hilfreich sein, um den bestmöglichen Ansatz für ein bestimmtes Szenario auszuwählen und einen Test von höchster Qualität zu erstellen , der sauber und wartbar ist.

Zum Beispiel könnten wir einen MessageController haben , der Nachrichten liefert. Es wird ein erhalten MessageDTO , und davon, es wird eine erstellen Nachricht von geliefert werden MessageService .

Unsere Überprüfung ist einfach. Stellen Sie sicher, dass wir den MessageService bei jeder Nachricht genau einmal aufgerufen haben :

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

Da die Nachricht innerhalb der zu testenden Methode erstellt wird , müssen wir any als Matcher verwenden .

Mit diesem Ansatz können wir die Daten in der Nachricht nicht validieren , was sich von den Daten in MessageDTO unterscheiden kann .

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

Um unseren Matcher zu verwenden, müssen wir unseren Test ändern und alle durch argThat ersetzen :

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

Jetzt wissen wir, dass unsere Nachrichteninstanz dieselben Daten wie unser MessageDTO hat .

5. Benutzerdefinierter Argument Matcher vs. ArgumentCaptor

Beide Techniken, benutzerdefinierte Argumentvergleicher und ArgumentCaptor, können verwendet werden, um sicherzustellen, dass bestimmte Argumente an Mocks übergeben wurden.

ArgumentCaptor passt jedoch möglicherweise besser, wenn es erforderlich ist, um Argumentwerte zu bestätigen, um die Überprüfung abzuschließen, oder wenn unser benutzerdefinierter Argumentvergleich wahrscheinlich nicht wiederverwendet wird .

Benutzerdefinierte Argument-Matcher über ArgumentMatcher eignen sich normalerweise besser zum Stubben.

6. Fazit

In diesem Artikel haben wir eine Funktion von Mockito , ArgumentMatcher und deren Unterschied zu ArgumentCaptor untersucht .

Wie immer ist der vollständige Quellcode der Beispiele auf GitHub verfügbar.