Beispiel für Mockitos argumentCaptor

Lesezeit: 7 Minuten

Benutzer-Avatar
Ujjwal

Kann mir bitte jemand ein Beispiel geben, das zeigt, wie man die verwendet org.mockito.ArgumentCaptor Klasse und wie es sich von unterscheidet einfache Matcher die mit mockito versehen sind.

Ich habe die bereitgestellten Mockito-Dokumente gelesen, aber diese veranschaulichen es nicht klar, keiner von ihnen kann es klar erklären.

  • Vielleicht finden Sie diesen Artikel nützlich: medium.com/javarevisited/… Es hat ein einfaches Beispiel

    – jagen

    25. Oktober 2021 um 19:50 Uhr

Benutzer-Avatar
Slawa Shpitalny

Ich stimme dem zu, was @fge gesagt hat, mehr noch. Schauen wir uns ein Beispiel an. Stellen Sie sich vor, Sie haben eine Methode:

class A {
    public void foo(OtherClass other) {
        SomeData data = new SomeData("Some inner data");
        other.doSomething(data);
    }
}

Wenn Sie nun die inneren Daten überprüfen möchten, können Sie den Captor verwenden:

// Create a mock of the OtherClass
OtherClass other = mock(OtherClass.class);

// Run the foo method with the mock
new A().foo(other);

// Capture the argument of the doSomething function
ArgumentCaptor<SomeData> captor = ArgumentCaptor.forClass(SomeData.class);
verify(other, times(1)).doSomething(captor.capture());

// Assert the argument
SomeData actual = captor.getValue();
assertEquals("Some inner data", actual.innerData);

  • Wenn doSomething(data) mutiert innerDatawird diese Änderung dann in vorhanden sein assertEquals("Some inner data", actual.innerData)oder wird innerData so erfasst werden, wie sie sind Vor doSomething wird hingerichtet?

    – Cory Klein

    5. Dezember 2018 um 18:28 Uhr

  • @CoryKlein Die OtherClass ist ein Schein, und wie es jetzt definiert wird doSomething() wird eigentlich nichts tun, es zeichnet einfach das Objekt auf, das übergeben wurde. Dies bedeutet, dass es so erfasst wird, wie es zuvor war doSomething wird ausgeführt.

    – Slava Spitalny

    7. Dezember 2018 um 16:18 Uhr

  • Im verify, times(1) ist der Standardwert und kann weggelassen werden.

    – Inego

    6. September 2019 um 6:43 Uhr

  • Woher weiß ArgumentCaptor, dass foo(other) passiert ist, da es erst nach dem Aufruf von foo(other) instanziiert wird?

    – Daniel Pop

    15. Juli 2020 um 6:38 Uhr

  • @AvramPop derjenige, der das weiß, ist das Scheinobjekt. Es enthält viele Informationen über den Mock. In all diesen Informationen enthält es auch den Aufrufverlauf für jede Methode mit ihren Parametern. Wenn Sie die anrufen verify -Methode werden diese Informationen verwendet, um Übereinstimmungen mit der von Ihnen durchgeführten Überprüfung auszuführen. Für jeden Parameter fragt es, ob es mit dem spezifischen Aufruf übereinstimmt, den es prüft. Wenn ArgumentCaptor aktiviert ist, speichert es einfach die Werte, mit denen es aufgerufen wurde, also wann verify endet, enthält es alle relevanten Aufrufe. So ungefähr funktioniert es. Ich hoffe es hilft

    – Slava Spitalny

    16. Juli 2020 um 10:15 Uhr


Die beiden Hauptunterschiede sind:

  • Wenn Sie auch nur ein einziges Argument erfassen, können Sie dieses Argument viel ausgefeilter und mit offensichtlicherem Code testen.
  • ein ArgumentCaptor erfassen kann mehr als einmal.

Um letzteres zu veranschaulichen, sagen Sie, Sie haben:

final ArgumentCaptor<Foo> captor = ArgumentCaptor.forClass(Foo.class);

verify(x, times(4)).someMethod(captor.capture()); // for instance

Dann kann der Captor Ihnen Zugriff auf alle 4 Argumente geben, mit denen Sie dann separat Assertionen durchführen können.

Dies oder eine beliebige Anzahl von Argumenten in der Tat, da a VerificationMode ist nicht auf eine feste Anzahl von Aufrufen beschränkt; In jedem Fall wird der Entführer Ihnen Zugang zu allen gewähren, wenn Sie dies wünschen.

Das hat auch den Vorteil, dass solche Tests (imho) viel einfacher zu schreiben sind, als eigene implementieren zu müssen ArgumentMatchers — besonders wenn Sie mockito mit assertj kombinieren.

Oh, und erwägen Sie bitte die Verwendung von TestNG anstelle von JUnit.

  • Was ist, wenn mehrere Parameter an die Methode übergeben werden – alle von unterschiedlichem Typ? Wie überprüfen Sie tatsächlich, ob der boolesche Parameter war Stimmtzum Beispiel.

    – IgorGanapolsky

    24. Februar 2017 um 14:37 Uhr


  • Können Sie Ihren Kommentar begründen: Oh, und erwägen Sie bitte die Verwendung von TestNG anstelle von JUnit.. Warum darüber nachdenken? Warum ändern?

    – Navitron

    9. Juni 2017 um 10:51 Uhr


  • @IgorGanapolsky Sie fügen einfach einen weiteren ArgumentCaptor hinzu. ArgumentCaptor arg = ArgumentCaptor.forClass(BigDecimal.class); ArgumentCaptor arg2 = ArgumentCaptor.forClass(String.class); Michael michael = neuer Michael(); michael.sayHi(j); verifiziere(j).saySomething(arg.capture(), arg2.capture()); System.out.println(“Wert ist ” + arg.getValue()); System.out.println(“String ist ” + arg2.getValue());

    – johnwick0831

    10. Mai 2018 um 3:15 Uhr


Benutzer-Avatar
Lho Ben

Die Schritte, um eine vollständige Überprüfung durchzuführen, sind:

Zuerstbereiten Sie den Argument Captor vor:

ArgumentCaptor<ArgumentClass> argumentCaptor = ArgumentCaptor.forClass(ArgumentClass.class);

Zweiteüberprüfen Sie den Aufruf an die abhängige Komponente (Mitarbeiter des zu testenden Subjekts).

times(1) ist der Standardwert, also muss er nicht hinzugefügt werden.

verify(dependentOnComponent, times(1)).method(argumentCaptor.capture());

Dritteerhalten Sie das an den Mitarbeiter übergebene Argument mit getValue() des Captors

ArgumentClass someArgument = messageCaptor.getValue();

Vierteverwenden Sie someArgument für Behauptungen

Ich habe dieses Beispiel erstellt, das einen sehr einfachen Dienst simuliert, der ein Repository verwendet, um einen String zu speichern (keine Abhängigkeitsinjektion, keine Entitäten), nur um ArgumentCaptor schnell beizubringen.

  • Der Dienst empfängt, wandelt einen Namen in Großbuchstaben um und kürzt ihn und ruft dann das Repository auf.
  • Das Repository “speichert” den String.
  • Mit ArgumentCaptor möchte ich wissen, welcher Wert an das Repository übergeben wird, und dann prüfen, ob er wie erwartet gekürzt und in Großbuchstaben ist

3 Klassen: PersonService, PersonRepository und PersonServiceTest (Pakete weggelassen)

public class PersonService {

    private PersonRepository personRepository;

    public void setPersonRepository(final PersonRepository personRepository) {
        this.personRepository = personRepository;
    }

    public void savePerson(final String name) {
        this.personRepository.save(name.toUpperCase().trim());
    }

}

public class PersonRepository {

    public void save(final String person) {
        System.out.println(".. saving person ..");
    }
}


import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;

class PersonServiceTest {

    @Test
    void testPersonService() {

        // Create the repository mock
        final PersonRepository personRepositoryMock = mock(PersonRepository.class);

        // Create the service and set the repository mock
        final PersonService personService = new PersonService();
        personService.setPersonRepository(personRepositoryMock);

        // Save a person
        personService.savePerson("Mario ");

        // Prepare an ArgumentCaptor to capture the value passed to repo.saveMethod
        final ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);

        // Capture the argument passed in the unique method invocation
        verify(personRepositoryMock, times(1)).save(captor.capture());

        // Check if the captured value is the expected one
        final String capturedParameter = captor.getValue();
        assertEquals("MARIO", capturedParameter);
    }
}

Hier gebe ich Ihnen ein richtiges Beispiel für eine Callback-Methode. Nehmen wir also an, wir haben eine Methode wie die Methode login() :

 public void login() {
    loginService = new LoginService();
    loginService.login(loginProvider, new LoginListener() {
        @Override
        public void onLoginSuccess() {
            loginService.getresult(true);
        }

        @Override
        public void onLoginFaliure() {
            loginService.getresult(false);

        }
    });
    System.out.print("@@##### get called");
}

Ich habe auch alle Hilfsklassen hier eingefügt, um das Beispiel klarer zu machen: loginService-Klasse

public class LoginService implements Login.getresult{
public void login(LoginProvider loginProvider,LoginListener callback){

    String username  = loginProvider.getUsername();
    String pwd  = loginProvider.getPassword();
    if(username != null && pwd != null){
        callback.onLoginSuccess();
    }else{
        callback.onLoginFaliure();
    }

}

@Override
public void getresult(boolean value) {
    System.out.print("login success"+value);
}}

und wir haben den Listener LoginListener als:

interface LoginListener {
void onLoginSuccess();

void onLoginFaliure();

}

jetzt wollte ich nur die Methode login() der Klasse Login testen

 @Test
public void loginTest() throws Exception {
    LoginService service = mock(LoginService.class);
    LoginProvider provider = mock(LoginProvider.class);
    whenNew(LoginProvider.class).withNoArguments().thenReturn(provider);
    whenNew(LoginService.class).withNoArguments().thenReturn(service);
    when(provider.getPassword()).thenReturn("pwd");
    when(provider.getUsername()).thenReturn("username");
    login.getLoginDetail("username","password");

    verify(provider).setPassword("password");
    verify(provider).setUsername("username");

    verify(service).login(eq(provider),captor.capture());

    LoginListener listener = captor.getValue();

    listener.onLoginSuccess();

    verify(service).getresult(true);

Vergessen Sie auch nicht, eine Anmerkung über der Testklasse als hinzuzufügen

@RunWith(PowerMockRunner.class)
@PrepareForTest(Login.class)

  • Sollte es sich nicht auf ArgumentCaptor beziehen?

    – Felipe Martins Melo

    29. Januar 2019 um 10:49 Uhr

  • Ja, wir erfassen den an die Methode login() übergebenen Listener im Beispiel login(LoginProvider loginProvider,LoginListener callback)

    – Vikram singh

    22. Februar 2019 um 11:55 Uhr


  • Wo ist der, die, das captor in Ihrer Antwort definiert?

    – tom_mai78101

    1. April 2020 um 17:37 Uhr

  • ArgumentCaptor< LoginListener > listenerCaptor = ArgumentCaptor.forClass(LoginListener.class);

    – Vikram singh

    14. Juni 2020 um 17:07 Uhr

  • Sollte es sich nicht auf ArgumentCaptor beziehen?

    – Felipe Martins Melo

    29. Januar 2019 um 10:49 Uhr

  • Ja, wir erfassen den an die Methode login() übergebenen Listener im Beispiel login(LoginProvider loginProvider,LoginListener callback)

    – Vikram singh

    22. Februar 2019 um 11:55 Uhr


  • Wo ist der, die, das captor in Ihrer Antwort definiert?

    – tom_mai78101

    1. April 2020 um 17:37 Uhr

  • ArgumentCaptor< LoginListener > listenerCaptor = ArgumentCaptor.forClass(LoginListener.class);

    – Vikram singh

    14. Juni 2020 um 17:07 Uhr

1352950cookie-checkBeispiel für Mockitos argumentCaptor

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy