Verwenden von Mockito ArgumentCaptor

1. Übersicht

In diesem Tutorial werden wir einen allgemeinen Anwendungsfall der Verwendung von Mockito ArgumentCaptor in unseren Komponententests behandeln.

Weitere Informationen zu anderen Anwendungsfällen von Mockito.verify finden Sie in unserem Mockito Verify-Kochbuch.

2. Verwenden von ArgumentCaptor

Mit ArgumentCaptor können wir ein an eine Methode übergebenes Argument erfassen, um es zu überprüfen. Dies ist besonders nützlich, wenn wir außerhalb der Methode, die wir testen möchten, nicht auf das Argument zugreifen können.

Stellen Sie sich beispielsweise eine EmailService- Klasse mit einer Sendemethode vor , die wir testen möchten :

public class EmailService { private DeliveryPlatform platform; public EmailService(DeliveryPlatform platform) { this.platform = platform; } public void send(String to, String subject, String body, boolean html) { Format format = Format.TEXT_ONLY; if (html) { format = Format.HTML; } Email email = new Email(to, subject, body); email.setFormat(format); platform.deliver(email); } ... }

In EmailService . Senden Sie , beachten Sie, wie platform.deliver eine neue E-Mail als Argument verwendet. Im Rahmen unseres Tests möchten wir überprüfen, ob das Formatfeld der neuen E-Mail auf Format.HTML festgelegt ist . Dazu müssen wir das an platform.deliver übergebene Argument erfassen und untersuchen .

Mal sehen, wie wir ArgumentCaptor verwenden können , um uns zu helfen.

2.1. Richten Sie den Unit Test ein

Lassen Sie uns zunächst unsere Unit-Test-Klasse erstellen:

@RunWith(MockitoJUnitRunner.class) public class EmailServiceUnitTest { @Mock DeliveryPlatform platform; @InjectMocks EmailService emailService; ... }

Wir verwenden die Annotation @Mock , um DeliveryPlatform zu verspotten , die automatisch mit der Annotation @InjectMocks in unseren EmailService eingefügt wird . Weitere Informationen finden Sie in unserem Artikel zu Mockito Annotations.

2.2. Fügen Sie ein ArgumentCaptor- Feld hinzu

Zweitens fügen wir ein neues ArgumentCaptor- Feld vom Typ Email hinzu , um unser erfasstes Argument zu speichern:

@Captor ArgumentCaptor emailCaptor;

2.3. Erfassen Sie das Argument

Drittens verwenden wir Mockito.verify mit dem ArgumentCaptor , um die E-Mail zu erfassen :

Mockito.verify(platform).deliver(emailCaptor.capture());

Wir können dann den erfassten Wert abrufen und als neues E-Mail- Objekt speichern :

Email emailCaptorValue = emailCaptor.getValue();

2.4. Überprüfen Sie den erfassten Wert

Lassen Sie uns zum Schluss den gesamten Test mit einer Bestätigung zur Überprüfung des erfassten E-Mail- Objekts betrachten:

@Test public void whenDoesSupportHtml_expectHTMLEmailFormat() { String to = "[email protected]"; String subject = "Using ArgumentCaptor"; String body = "Hey, let'use ArgumentCaptor"; emailService.send(to, subject, body, true); Mockito.verify(platform).deliver(emailCaptor.capture()); Email value = emailCaptor.getValue(); assertEquals(Format.HTML, value.getFormat()); }

3. Stubbing vermeiden

Obwohl wir einen ArgumentCaptor mit Stubbing verwenden können , sollten wir dies generell vermeiden. In Mockito bedeutet dies im Allgemeinen, dass die Verwendung eines ArgumentCaptor mit Mockito.when vermieden wird . Beim Stubbing sollten wir stattdessen einen ArgumentMatcher verwenden.

Schauen wir uns ein paar Gründe an, warum wir Stubbing vermeiden sollten.

3.1. Verminderte Testlesbarkeit

Betrachten Sie zunächst einen einfachen Test :

Credentials credentials = new Credentials("baeldung", "correct_password", "correct_key"); Mockito.when(platform.authenticate(Mockito.eq(credentials))) .thenReturn(AuthenticationStatus.AUTHENTICATED); assertTrue(emailService.authenticatedSuccessfully(credentials));

Hier verwenden wir Mockito.eq (Anmeldeinformationen), um anzugeben, wann der Mock ein Objekt zurückgeben soll.

Betrachten Sie als Nächstes denselben Test mit einem ArgumentCaptor :

Credentials credentials = new Credentials("baeldung", "correct_password", "correct_key"); Mockito.when(platform.authenticate(credentialsCaptor.capture())) .thenReturn(AuthenticationStatus.AUTHENTICATED); assertTrue(emailService.authenticatedSuccessfully(credentials)); assertEquals(credentials, credentialsCaptor.getValue());

Beachten Sie im Gegensatz zum ersten Test, wie wir in der letzten Zeile eine zusätzliche Zusicherung durchführen müssen, um dasselbe wie bei Mockito.eq (Anmeldeinformationen) zu tun .

Beachten Sie schließlich, dass nicht sofort klar ist, worauf sich credentialsCaptor.capture () bezieht. Dies liegt daran, dass wir den Captor außerhalb der Zeile erstellen müssen, in der wir ihn verwenden, was die Lesbarkeit verringert.

3.2. Reduzierte Fehlerlokalisierung

Ein weiterer Grund ist, dass wir eine Ausnahme erhalten , wenn emailService.authenticatedSuccessfully nicht platform.authenticate aufruft :

org.mockito.exceptions.base.MockitoException: No argument value was captured!

Dies liegt daran, dass unsere Stubbed-Methode kein Argument erfasst hat. Das eigentliche Problem liegt jedoch nicht in unserem Test selbst, sondern in der tatsächlichen Methode, die wir testen.

Mit anderen Worten, es führt uns zu einer Ausnahme im Test, während der eigentliche Fehler in der Methode liegt, die wir testen.

4. Fazit

In diesem kurzen Tutorial haben wir uns einen allgemeinen Anwendungsfall für die Verwendung von ArgumentCaptor angesehen . Wir haben uns auch die Gründe angesehen, warum ArgumentCaptor nicht mit Stubbing verwendet werden sollte. Wie üblich sind alle unsere Codebeispiele auf GitHub verfügbar.