Mockito Argument Matcher: any(), eq(), ArgumentCaptor und benutzerdefinierte Matcher verwenden
Mit Mockito Argument Matchern lassen sich Methodenaufrufe stubben und überprüfen, ohne für jedes Argument einen festen Wert im Test vorgeben zu müssen. In Kombination mit when() und verify() können Bedingungen wie „beliebiger String“ oder „genau diese ID“ definiert werden, während der Testcode übersichtlich bleibt. Dieser Leitfaden behandelt die integrierten Matcher, die Konsistenzregel zur Vermeidung einer InvalidUseOfMatchersException, den ArgumentCaptor sowie eigene ArgumentMatcher-Implementierungen mit aktuellen Mockito-5.x-APIs und JUnit 5.
Wichtige Erkenntnisse
- Mockito Argument Matcher befinden sich in
org.mockito.ArgumentMatchersund sollten ausschließlich innerhalb vonwhen(),verify()sowie verwandten Stubbing-Hilfsmethoden wiedoNothing().when()eingesetzt werden. - Sobald ein Parameter einen Matcher verwendet, müssen auch alle anderen Parameter desselben Methodenaufrufs als Matcher angegeben werden. Literale Werte sollten deshalb mit
eq()umschlossen werden, anstatt sie direkt zu übergeben. - Typisierte Matcher wie
anyString(),anyInt()undanyList()sind für primitive Typen und Referenzen in der Regel gegenüber dem allgemeinenany()zu bevorzugen, da sich dadurch Probleme mitnullund Unboxing reduzieren lassen. - Ein
ArgumentCaptoreignet sich, wenn nach einem Methodenaufruf geprüft werden soll, welcher Wert tatsächlich übergeben wurde.argThat()in Verbindung mit einem eigenenArgumentMatcherist sinnvoll, wenn wiederverwendbare Matching-Logik direkt innerhalb einer Stubbing- oder Verifikationsanweisung benötigt wird. - Matcher speichern Erwartungen intern auf einem Stack und liefern Platzhalterwerte zurück. Daher sollten sie niemals außerhalb einer Stubbing- oder Verifikationsanweisung aufgerufen werden.
Voraussetzungen
- Java 11 oder eine neuere Version. Falls eine lokale Laufzeitumgebung benötigt wird, kann eine passende Java-Installationsanleitung für das verwendete Betriebssystem genutzt werden.
- Ein Maven- oder Gradle-Projekt mit JUnit 5 und Mockito 5.x. Die folgenden Beispiele verwenden Mockito
5.14.2und JUnit Jupiter5.10.2. - Grundkenntnisse im Umgang mit Mockito-Mocks und der Überprüfung von Methodenaufrufen.
- Optional sind grundlegende Kenntnisse zu JUnit 5 und zur allgemeinen Verwendung von Mockito hilfreich.
Maven-Testabhängigkeiten:
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>5.14.2</version>
<scope>test</scope>
</dependency>
Die Matcher können in den Testklassen statisch importiert werden:
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
Was sind Mockito Argument Matcher?
Mockito Argument Matcher sind Hilfsmethoden, mit denen sich flexible Bedingungen für Methodenparameter beim Stubbing oder bei der Verifikation definieren lassen. Anstatt ausschließlich einen exakten Wert über equals() zu vergleichen, kann ein Matcher beispielsweise jeden String, einen positiven int-Wert oder einen Wert akzeptieren, der einer individuellen fachlichen Bedingung entspricht.
Wie Argument Matcher in Mockito funktionieren
Während eine Stubbing- oder Verifikationsanweisung aufgebaut wird, legt Mockito die verwendeten Matcher auf einem internen Stack ab. Methoden wie anyInt() geben sichere Platzhalterwerte zurück. Für anyInt() ist dies beispielsweise 0. Dadurch kann der Java-Compiler Ausdrücke wie when(mock.get(anyInt())) verarbeiten. Der eigentliche Vergleich erfolgt später, wenn Mockito die gespeicherten Matcher auf die Argumente eines tatsächlichen Methodenaufrufs anwendet. Weitere Informationen enthält die ArgumentMatchers Javadoc.
Wann Matcher anstelle exakter Werte verwendet werden sollten
Exakte Werte beziehungsweise eq() eignen sich, wenn ein Test gezielt von einer bestimmten Eingabe abhängt. Matcher sind sinnvoll, wenn der konkrete Wert keine Rolle spielt, zwischen verschiedenen Testfällen variiert oder einer bestimmten Bedingung wie einem Typ, einem Wertebereich oder einer Zeichenfolge entsprechen muss. Eine übermäßige Verwendung von any() kann Fehler verdecken. Deshalb sind konkrete Werte häufig die bessere Ausgangsbasis, während Matcher vor allem dann eingesetzt werden sollten, wenn sie unnötige Wiederholungen vermeiden.
Die folgende Beispielklasse wird in den weiteren Beispielen verwendet:
public class Foo {
public boolean bool(String str, int i, Object obj) {
return false;
}
public int in(boolean b, java.util.List<String> strs) {
return 0;
}
public int bar(byte[] bytes, String[] s, int i) {
return 0;
}
public void log(String message) {
// no-op
}
}
Die Konsistenzregel für Mockito Argument Matcher
Mockito verlangt, dass innerhalb eines bestimmten Stubbing- oder Verifikationsaufrufs entweder alle Parameter Matcher verwenden oder kein Parameter einen Matcher verwendet. Wird ein Matcher mit einem unveränderten Literal kombiniert, entsteht eine InvalidUseOfMatchersException.
Warum Matcher und exakte Werte nicht gemischt werden dürfen
Matcher-Argumente und direkte Werte werden innerhalb von Mockito über unterschiedliche Mechanismen verarbeitet. Ein Ausdruck wie when(mock.bool(anyString(), 1, any())) ist deshalb ungültig, da 1 als direkter Wert übergeben wird, während die anderen Parameter Matcher verwenden.
Falsch:
when(mockFoo.bool(anyString(), 1, any(Object.class))).thenReturn(true); // throws
Richtig:
when(mockFoo.bool(anyString(), eq(1), any(Object.class))).thenReturn(true);
Dieselbe Regel gilt auch für verify():
verify(mockFoo).bool(eq("hello"), anyInt(), any(Object.class));
So lässt sich eine InvalidUseOfMatchersException beheben
- Jeder direkte Wert kann mit einem Matcher wie
eq(),eq(1)odereq("hello")umschlossen werden. - Alternativ können sämtliche Matcher entfernt und ausschließlich konkrete Argumentwerte verwendet werden.
- Die Rückgabewerte von Matchern sollten nicht in Variablen gespeichert und später in anderen Stubbing-Anweisungen wiederverwendet werden.
Integrierte Argument Matcher in Mockito
Die folgende Tabelle zeigt häufig eingesetzte Matcher in Mockito 5.x. Typisierte Referenz-Matcher wie anyString() akzeptieren kein null. Für Parameter, die null enthalten dürfen, können stattdessen isNull() oder isNotNull() verwendet werden.
| Matcher | Akzeptierte Typen | Verhalten bei null | Typischer Anwendungsfall |
|---|---|---|---|
any() |
Beliebige Referenzen, Varargs | Erlaubt null | Flexibler Abgleich von Referenzen |
any(Class<T>) |
Typ T |
Schließt null aus | Typsicherer Objektvergleich |
eq(value) |
Derselbe Typ wie der Wert | Verwendet das Verhalten von equals() |
Exakte Werte innerhalb von Matcher-Ausdrücken |
anyString() |
String |
Schließt null aus | Beliebige nicht leere String-Referenz |
anyInt() |
int oder Integer |
Schließt einen null-Wrapper aus | Primitive oder gekapselte Ganzzahlen |
anyList() |
List |
Schließt null aus | Beliebige nicht-null Liste |
isNull() / isNotNull() |
Referenztypen | Explizite Prüfung auf null | Parameter, die null enthalten dürfen |
contains(), startsWith(), endsWith() |
String |
Schließt null aus | Teilweiser Vergleich von Zeichenfolgen |
any() und any(Class) für typbasierte Vergleiche verwenden
any() akzeptiert jede Objektreferenz einschließlich null und kann außerdem für Varargs verwendet werden. any(Foo.class) führt dagegen eine Typprüfung durch und akzeptiert kein null. Wenn der erwartete Typ im Test deutlich sichtbar sein soll, ist any(Class) meist die klarere Variante.
Foo mockFoo = mock(Foo.class);
when(mockFoo.bool(anyString(), anyInt(), any(Object.class))).thenReturn(true);
assertTrue(mockFoo.bool("A", 1, "A"));
assertTrue(mockFoo.bool("B", 10, new Object()));
Bei Array-Parametern wird die entsprechende Array-Klasse angegeben:
when(mockFoo.bar(any(byte[].class), any(String[].class), anyInt())).thenReturn(1);
eq() für exakte Werte innerhalb von Matcher-Ketten verwenden
Wenn mindestens ein Argument eines Aufrufs einen Matcher verwendet, müssen Werte, die exakt übereinstimmen sollen, mit eq() angegeben werden:
when(mockFoo.bool(eq("false"), anyInt(), any(Object.class))).thenReturn(false);
assertFalse(mockFoo.bool("false", 10, new Object()));
Werden keine anderen Matcher verwendet, können direkte Werte übergeben werden: when(mockFoo.bool("false", 10, obj)).
anyString(), anyInt(), anyList() und weitere typisierte Matcher verwenden
Typisierte Matcher verbessern die Lesbarkeit von Tests und können insbesondere bei primitiven Parametern Probleme durch Autoboxing vermeiden:
when(mockFoo.in(anyBoolean(), anyList())).thenReturn(10);
Für Collections stellt Mockito außerdem Matcher wie anySet(), anyMap() und anyCollection() bereit.
isNull() und isNotNull() verwenden
when(mockFoo.bool(isNull(), anyInt(), isNotNull())).thenReturn(true);
assertTrue(mockFoo.bool(null, 1, "payload"));
contains(), startsWith() und endsWith() für String-Vergleiche verwenden
when(mockFoo.bool(startsWith("ERR"), anyInt(), any())).thenReturn(false);
mockFoo.bool("ERR-404", 0, null);
verify(mockFoo).bool(contains("ERR"), anyInt(), any());
Mockito Argument Matcher mit when() für Stubbing verwenden
Stubbing mit any() und eq() kombinieren
Foo mockFoo = mock(Foo.class);
when(mockFoo.bool(anyString(), anyInt(), any(Object.class))).thenReturn(true);
when(mockFoo.bool(eq("false"), anyInt(), any(Object.class))).thenReturn(false);
Mockito wertet Stubs entsprechend ihrer Deklarationsreihenfolge aus. Überschneiden sich mehrere Matching-Muster, sollte der spezifischere Stub nach dem allgemeineren Stub definiert werden.
Methoden mit mehreren Parametern und void-Methoden stubben
Für eine void-Methode kann doNothing() verwendet werden. Argument Matcher funktionieren dabei nach demselben Prinzip:
doNothing().when(mockFoo).log(anyString());
mockFoo.log("ready");
Mockito Argument Matcher mit verify() zur Verhaltensprüfung verwenden
Argument Matcher sind für verify() und die Stubbing-APIs vorgesehen. Sie dienen nicht als allgemeine boolesche Prüfungen.
Einen Methodenaufruf mit bestimmten Parametertypen überprüfen
verify(mockFoo, atLeastOnce()).bool(anyString(), anyInt(), any(Object.class));
verify(mockFoo).bool(eq("false"), anyInt(), any(Object.class));
verify() mit times(), never() und atLeast() kombinieren
verify(mockFoo, times(1)).log(anyString());
verify(mockFoo, never()).bool(eq("skip"), anyInt(), any());
verify(mockFoo, atLeast(0)).in(anyBoolean(), anyList());
Wenn zusätzlich die Reihenfolge der Methodenaufrufe überprüft werden soll, kann InOrder eingesetzt werden:
InOrder inOrder = inOrder(mockFoo);
inOrder.verify(mockFoo).log(anyString());
inOrder.verify(mockFoo).bool(anyString(), anyInt(), any());
Mockito-Argumente mit ArgumentCaptor erfassen
Ein ArgumentCaptor speichert die Argumente, die an einen Mock übergeben wurden, damit deren tatsächliche Werte anschließend überprüft werden können. Captors und Matcher erfüllen dabei unterschiedliche, sich ergänzende Aufgaben: Matcher definieren, welche Werte akzeptiert werden, während Captors Zugriff auf die tatsächlich verwendeten Werte ermöglichen.
Wann ArgumentCaptor anstelle eines Matchers verwendet werden sollte
Ein Captor ist besonders geeignet, wenn nach einem Methodenaufruf mehrere Prüfungen für dasselbe Objekt durchgeführt werden sollen, beispielsweise für einzelne Felder, die Größe einer Collection oder daraus berechnete Werte. Wenn eine einfache Bedingung während des Stubbings oder der Verifikation ausreicht, ist ein Matcher meist die passendere Wahl.
ArgumentCaptor<String> messageCaptor = ArgumentCaptor.forClass(String.class);
mockFoo.log("shipped");
verify(mockFoo).log(messageCaptor.capture());
assertEquals("shipped", messageCaptor.getValue());
ArgumentCaptor bei einzelnen und mehreren Aufrufen
mockFoo.log("first");
mockFoo.log("second");
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
verify(mockFoo, times(2)).log(captor.capture());
assertEquals(List.of("first", "second"), captor.getAllValues());
ArgumentCaptor im Vergleich zu einem eigenen ArgumentMatcher
| Ansatz | Besonders geeignet für | Nachteil |
|---|---|---|
ArgumentCaptor |
Untersuchung tatsächlich übergebener Argumentinstanzen nach einem Aufruf | Erfordert einen zusätzlichen Verifikationsschritt und ist nicht für die Definition von Stubbing-Rückgabewerten gedacht |
argThat(ArgumentMatcher) |
Wiederverwendbare Inline-Bedingungen beim Stubbing oder bei der Verifikation | Bietet weniger direkten Einblick in den tatsächlichen Wert, solange keine Verifikation fehlschlägt |
eq() / typisierte any*()-Matcher |
Einfache und kompakte Tests | Weniger ausdrucksstark bei komplexen fachlichen Bedingungen |
Einen eigenen Mockito ArgumentMatcher erstellen
Wenn die integrierten Matcher eine benötigte Bedingung nicht ausdrücken können, kann org.mockito.ArgumentMatcher<T> implementiert werden. Die eigene Matching-Logik wird anschließend über argThat() eingebunden.
Das ArgumentMatcher-Interface implementieren
import org.mockito.ArgumentMatcher;
public class PremiumOrderMatcher implements ArgumentMatcher<Order> {
@Override
public boolean matches(Order order) {
return order != null && order.getTotalCents() >= 10_000;
}
}
Beispiel für einen eigenen ArgumentMatcher mit einem Domänenobjekt
public class Order {
private final int totalCents;
public Order(int totalCents) { this.totalCents = totalCents; }
public int getTotalCents() { return totalCents; }
}
public class OrderService {
public boolean isPremium(Order order) {
return order != null && order.getTotalCents() >= 10_000;
}
}
Einen eigenen ArgumentMatcher in Tests registrieren und verwenden
OrderService service = mock(OrderService.class);
when(service.isPremium(argThat(new PremiumOrderMatcher()))).thenReturn(true);
assertTrue(service.isPremium(new Order(15_000)));
Ab Java 8 kann alternativ eine Lambda-Funktion eingesetzt werden:
when(service.isPremium(argThat(o -> o.getTotalCents() > 5_000))).thenReturn(true);
Weitere Hinweise zur Gestaltung eigener Matcher enthält die ArgumentMatcher Javadoc des Mockito-Teams.
Mockito AdditionalMatchers
org.mockito.AdditionalMatchers stellt zusätzliche Hilfsmethoden für numerische Vergleiche und die Prüfung der Gleichheit von Arrays zur Verfügung:
import static org.mockito.AdditionalMatchers.*;
when(mockFoo.bar(any(byte[].class), aryEq(new String[] { "A", "B" }), gt(10))).thenReturn(11);
assertEquals(11, mockFoo.bar("abc".getBytes(), new String[] { "A", "B" }, 20));
Weitere Hilfsmethoden sind unter anderem lt(), or(), and() und not(), mit denen sich zusätzliche oder kombinierte Bedingungen definieren lassen.
Häufige Fehler bei Mockito Argument Matchern und wie sie vermieden werden
Matcher und direkte Werte miteinander kombinieren
Sobald ein Parameter einen Matcher verwendet, sollten direkte Werte innerhalb desselben Aufrufs mit eq() in Matcher umgewandelt werden.
Argument Matcher außerhalb von when() oder verify() verwenden
String value = anyString(); // wrong: matcher used outside stub/verify
Matcher müssen unmittelbar innerhalb des Aufrufs der gemockten Methode stehen, der an when() oder verify() übergeben wird.
any() zu häufig verwenden und dadurch echte Fehler übersehen
Bei geschäftskritischen Parametern wie Kennungen oder Währungswerten sollten möglichst exakte Werte verwendet werden. Matcher sind dafür gedacht, unnötigen Testcode zu reduzieren, nicht jedoch wichtige Prüfungen zu entfernen.
Mockito Argument Matcher im Vergleich zu Hamcrest Matchern
Seit Mockito 2.1 ist Mockito nicht mehr direkt von Hamcrest abhängig. Wenn eine Integration mit Hamcrest benötigt wird, kann das Artefakt mockito-hamcrest hinzugefügt und MockitoHamcrest.argThat(org.hamcrest.Matcher) anstelle der veralteten APIs aus org.mockito.Matchers verwendet werden. Für die meisten Projekte sind die integrierten Mockito-Matcher zusammen mit argThat(ArgumentMatcher) einfacher und vermeiden eine zusätzliche Abhängigkeit.
| Werkzeug | Einstiegspunkt | Wann es verwendet werden sollte |
|---|---|---|
Mockito ArgumentMatchers |
any(), eq(), contains() |
Standardwahl für Mockito-Tests |
Eigener ArgumentMatcher mit argThat() |
argThat(predicate) |
Fachspezifische Matching-Regeln, die in mehreren Tests wiederverwendet werden |
Hamcrest über MockitoHamcrest |
MockitoHamcrest.argThat(hasItem(...)) |
Bereits vorhandene Hamcrest-Prüfungen, die weiterhin im Projekt eingesetzt werden |
Das passende Mockito-Matching-Werkzeug auswählen
| Anforderung | Geeignete Lösung |
|---|---|
| Einen Parameterwert ignorieren | anyString(), anyInt(), any(MyDto.class) |
| Einen exakten Wert zwischen anderen Matchern verlangen | eq("literal") |
| Den tatsächlich übergebenen Wert untersuchen | ArgumentCaptor |
| Eine komplexe, wiederverwendbare Regel anwenden | Eigener ArgumentMatcher über argThat() |
| Eine void-Methode stubben | doNothing().when(mock).method(any()) |
Häufig gestellte Fragen zu Mockito Argument Matchern
1. Was sind Argument Matcher in Mockito?
Argument Matcher sind statische Methoden wie anyString(), eq() und argThat(), mit denen festgelegt wird, wie Mockito Parameter beim Stubbing oder bei der Verifikation vergleichen soll. Dadurch sind flexible Vergleiche möglich, wenn konkrete Werte nicht bekannt oder für den jeweiligen Test nicht relevant sind. Wird für einen Parameter ein Matcher verwendet, müssen auch alle übrigen Parameter desselben Aufrufs Matcher verwenden.
2. Was ist der Unterschied zwischen eq() und any()?
eq(value) verlangt, dass ein übergebenes Argument gemäß equals() beziehungsweise bei primitiven Werten über == mit value übereinstimmt. any() und typisierte Varianten wie anyString() akzeptieren dagegen einen größeren Bereich von Werten, sofern diese die jeweilige Typ- oder Matching-Bedingung erfüllen. eq() eignet sich, wenn ausschließlich ein bestimmter Wert akzeptiert werden soll. any*() ist sinnvoll, wenn der genaue Wert keine Rolle spielt.
3. Müssen alle Argumente Matcher verwenden, sobald ein Matcher eingesetzt wird?
Ja. Mockito verlangt innerhalb jedes einzelnen Stubbing- oder verify()-Aufrufs eine konsistente Verwendung von Matchern. Wird beispielsweise anyString() zusammen mit einem unveränderten Literal verwendet, führt dies zu einer InvalidUseOfMatchersException. Direkte Werte müssen entweder mit eq() umschlossen oder sämtliche Matcher aus diesem Aufruf entfernt werden.
4. Wann sollte eq() in Mockito verwendet werden?
eq() sollte eingesetzt werden, wenn mindestens ein anderer Parameter desselben Methodenaufrufs bereits einen Matcher verwendet und für einen bestimmten Parameter trotzdem ein exakter Wert verlangt wird. Bestehen alle Argumente ausschließlich aus normalen Literalen und werden keine Matcher eingesetzt, ist eq() nicht erforderlich.
5. Was macht Mockito any()?
any() akzeptiert für Referenzparameter jede Objektreferenz einschließlich null. Typisierte Alternativen wie anyInt() und any(Order.class) begrenzen die möglichen Treffer auf entsprechende primitive Typen oder Instanzen einer bestimmten Klasse. Seit Mockito 2.1.0 schließen diese typisierten Matcher null aus. Für klarere und sicherere Tests sind typisierte Matcher deshalb häufig die bessere Wahl.
Fazit
Mockito Argument Matcher erleichtern die Erstellung gezielter Unit-Tests, indem sie beim Stubbing und bei der Verifikation flexible Bedingungen für Parameter ermöglichen. Dafür stehen unter anderem any(), eq(), typisierte Matcher, ArgumentCaptor und eigene ArgumentMatcher-Implementierungen zur Verfügung. Wichtig ist die Regel, Matcher innerhalb eines Methodenaufrufs konsequent für alle Argumente einzusetzen. Für primitive Werte und Collections sind typisierte Matcher in der Regel vorzuziehen, während Captors dann sinnvoll sind, wenn der tatsächlich übergebene Zustand eines Arguments nach dem Methodenaufruf untersucht werden soll.


