wake-up-neo.com

Wie man mit Mockito leere Methoden verspottet

Wie man Methoden mit ungültigem Rückgabetyp verspottet?

Ich habe ein Beobachtermuster implementiert, kann es aber nicht mit Mockito verspotten, weil ich nicht weiß, wie.

Und ich habe versucht, ein Beispiel im Internet zu finden, aber es ist mir nicht gelungen.

Meine Klasse sieht so aus:

public class World {

    List<Listener> listeners;

    void addListener(Listener item) {
        listeners.add(item);
    }

    void doAction(Action goal,Object obj) {
        setState("i received");
        goal.doAction(obj);
        setState("i finished");
    }

    private string state;
    //setter getter state
} 

public class WorldTest implements Listener {

    @Test public void Word{
    World  w= mock(World.class);
    w.addListener(this);
    ...
    ...

    }
}

interface Listener {
    void doAction();
}

Das System wird nicht mit Mock ausgelöst. = (Ich möchte den oben genannten Systemstatus anzeigen und die entsprechenden Aussagen treffen.

837
ibrahimyilmaz

Die Lösung des sogenannten Problems ist die Verwendung eines spyMockito.spy (...) anstelle eines mockMockito.mock (..) .

Mit Spy können wir uns teilweise lustig machen. Mockito ist in dieser Sache gut. Da Sie eine Klasse haben, die nicht vollständig ist, verspotten Sie auf diese Weise einen erforderlichen Platz in dieser Klasse.

54
ibrahimyilmaz

Schauen Sie sich die Mockito API docs an. Wie im verknüpften Dokument erwähnt (Punkt 12), können Sie eine der Methodenfamilien doThrow(), doAnswer(), doNothing(), doReturn() aus dem Mockito-Framework verwenden, um ungültige Methoden zu verspotten.

Zum Beispiel,

Mockito.doThrow(new Exception()).when(instance).methodName();

oder wenn Sie es mit Follow-up-Verhalten kombinieren möchten,

Mockito.doThrow(new Exception()).doNothing().when(instance).methodName();

Angenommen, Sie möchten den Setter setState(String s) in der folgenden Klassenwelt verspotten: Der Code verwendet die Methode doAnswer, um die Methode setState zu verspotten.

World  mockWorld = mock(World.class); 
doAnswer(new Answer<Void>() {
    public Void answer(InvocationOnMock invocation) {
      Object[] args = invocation.getArguments();
      System.out.println("called with arguments: " + Arrays.toString(args));
      return null;
    }
}).when(mockWorld).setState(anyString());
1047
sateesh

Ich denke, ich habe eine einfachere Antwort auf diese Frage gefunden, um die echte Methode für nur eine Methode aufzurufen (auch wenn sie eine ungültige Rückgabe hat), können Sie dies tun:

Mockito.doCallRealMethod().when(<objectInstance>).<method>();
<objectInstance>.<method>();

Oder Sie können die reale Methode für alle Methoden dieser Klasse folgendermaßen aufrufen:

<Object> <objectInstance> = mock(<Object>.class, Mockito.CALLS_REAL_METHODS);
95
MarcioB

Wenn Sie zu dem, was @sateesh sagte, nur eine void-Methode verspotten möchten, um zu verhindern, dass der Test sie aufruft, können Sie Spy folgendermaßen verwenden:

World world = new World();
World spy = Mockito.spy(world);
Mockito.doNothing().when(spy).methodToMock();

Wenn Sie Ihren Test ausführen möchten, stellen Sie sicher, dass Sie die Methode in test für das Objekt spy und nicht für das Objekt world aufrufen. Zum Beispiel:

assertEquals(0,spy.methodToTestThatShouldReturnZero());
63
Omri374

Zuallererst: Sie sollten immer mockito static importieren, damit der Code viel besser lesbar (und intuitiver) ist:

import static org.mockito.Mockito.*;

Für das teilweise Verspotten und das Beibehalten der ursprünglichen Funktionalität bietet mockito "Spy" an.

Sie können es wie folgt verwenden:

private World world = spy(World.class);

Um zu verhindern, dass eine Methode ausgeführt wird, können Sie Folgendes verwenden:

doNothing().when(someObject).someMethod(anyObject());

um einer Methode ein benutzerdefiniertes Verhalten zu verleihen, verwenden Sie "when" mit einem "thenReturn":

doReturn("something").when(this.world).someMethod(anyObject());

Weitere Beispiele finden Sie in den Mockito-Beispielen im Dokument.

25
fl0w

Wie man ungültige Methoden mit mockito verspottet - es gibt zwei Möglichkeiten:

  1. doAnswer - Wenn wir möchten, dass unsere verspottete Void-Methode etwas tut (verspotten Sie das Verhalten, obwohl es nichtig ist).
  2. doThrow - Dann gibt es Mockito.doThrow(), wenn Sie eine Ausnahme von der Methode "Mocked Void" auslösen möchten.

Das Folgende ist ein Beispiel für die Verwendung (kein idealer Anwendungsfall, sondern wollte nur die grundlegende Verwendung veranschaulichen).

@Test
public void testUpdate() {

    doAnswer(new Answer<Void>() {

        @Override
        public Void answer(InvocationOnMock invocation) throws Throwable {
            Object[] arguments = invocation.getArguments();
            if (arguments != null && arguments.length > 1 && arguments[0] != null && arguments[1] != null) {

                Customer customer = (Customer) arguments[0];
                String email = (String) arguments[1];
                customer.setEmail(email);

            }
            return null;
        }
    }).when(daoMock).updateEmail(any(Customer.class), any(String.class));

    // calling the method under test
    Customer customer = service.changeEmail("[email protected]", "[email protected]");

    //some asserts
    assertThat(customer, is(notNullValue()));
    assertThat(customer.getEmail(), is(equalTo("[email protected]")));

}

@Test(expected = RuntimeException.class)
public void testUpdate_throwsException() {

    doThrow(RuntimeException.class).when(daoMock).updateEmail(any(Customer.class), any(String.class));

    // calling the method under test
    Customer customer = service.changeEmail("[email protected]", "[email protected]");

}
}

Weitere Informationen zum Verspotten und Testen Methoden mit Mockito in meinem Beitrag nichtig machen Wie man mit Mockito spottet (Eine umfassende Anleitung mit Beispielen)

19

Hinzufügen einer weiteren Antwort zum Haufen (kein Wortspiel beabsichtigt) ...

Sie müssen die Methode doAnswer aufrufen, wenn Sie den Spion nicht verwenden können oder wollen. Sie müssen jedoch nicht unbedingt Ihr eigenes Answer würfeln. Es gibt mehrere Standardimplementierungen. Insbesondere CallsRealMethods .

In der Praxis sieht es ungefähr so ​​aus:

doAnswer(new CallsRealMethods()).when(mock)
        .voidMethod(any(SomeParamClass.class));

Oder:

doAnswer(Answers.CALLS_REAL_METHODS.get()).when(mock)
        .voidMethod(any(SomeParamClass.class));
14
javamonkey79

In Java 8 kann dies etwas übersichtlicher gestaltet werden, vorausgesetzt, Sie haben einen statischen Import für org.mockito.Mockito.doAnswer:

doAnswer(i -> {
  // Do stuff with i.getArguments() here
  return null;
}).when(*mock*).*method*(*methodArguments*);

Der return null; ist wichtig, und ohne ihn schlägt die Kompilierung mit einigen ziemlich undurchsichtigen Fehlern fehl, da für doAnswer kein passender Override gefunden werden kann.

Zum Beispiel könnte ein ExecutorService, das gerade ein Runnable ausführt, das an execute() übergeben wurde, implementiert werden mit:

doAnswer(i -> {
  ((Runnable) i.getArguments()[0]).run();
  return null;
}).when(executor).execute(any());
8
Tim B

Ich denke, Ihre Probleme sind auf Ihre Teststruktur zurückzuführen. Ich fand es schwierig, das Verspotten mit der herkömmlichen Methode zum Implementieren von Schnittstellen in der Testklasse zu mischen (wie Sie es hier getan haben).

Wenn Sie den Listener als Mock implementieren, können Sie die Interaktion überprüfen.

Listener listener = mock(Listener.class);
w.addListener(listener);
world.doAction(..);
verify(listener).doAction();

Dies sollte dich befriedigen, dass die 'Welt' das Richtige tut.

5
ashley

@ashley: funktioniert bei mir

public class AssetChangeListenerImpl extends
AbstractAssetChangeListener implements AssetChangeListener {

  @Override
  public void onChangeEvent(final EventMessage message) throws EventHubClientException {
      execute(message);
    }
  }
}

public class AbstractAssetChangeListener {
  protected  void execute( final EventMessage message ) throws EventHubClientException {
    executor.execute( new PublishTask(getClient(), message) );
} } @RunWith(MockitoJUnitRunner.class) public class AssetChangeListenerTest extends AbstractAssetChangeListenerTest {

 public void testExecute() throws EventHubClientException {
    EventMessage message = createEventMesage(EventType.CREATE);
    assetChangeListener.execute(message);
    verify(assetChangeListener, times(1)).execute(message);
} }
0
Yoga Gowda