web-dev-qa-db-fra.com

Comment se moquer des méthodes de vide avec Mockito

Comment se moquer des méthodes avec le type de retour vide?

J'ai implémenté un motif d'observateur mais je ne peux pas me moquer de lui avec Mockito car je ne sais pas comment.

Et j'ai essayé de trouver un exemple sur Internet, mais sans succès.

Ma classe ressemble à ceci:

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

Les systèmes ne sont pas déclenchés avec mock. = (Je veux montrer l’état du système mentionné ci-dessus. Et faire une affirmation en fonction de ceux-ci.

837
ibrahimyilmaz

La solution du problème dit consiste à utiliser un spyMockito.spy (...) au lieu d'un mockMockito.mock (..) .

Spy nous permet de nous moquer partiellement. Mockito est bon dans cette affaire. Comme vous avez une classe incomplète, vous vous moquez de la place requise dans cette classe.

54
ibrahimyilmaz

Jetez un coup d'œil au Mockito docs de l'API . Comme le document lié le mentionne (Point 12), vous pouvez utiliser l’un des doThrow(), doAnswer(), doNothing(), doReturn() méthodes de Mockito pour simuler des méthodes vides.

Par exemple,

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

ou si vous voulez le combiner avec un comportement de suivi,

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

En supposant que vous cherchiez à vous moquer du paramètre setState(String s) dans la classe World ci-dessous, le code utilise la méthode doAnswer pour se moquer de setState.

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

Je pense avoir trouvé une réponse plus simple à cette question. Pour appeler la vraie méthode pour une seule méthode (même si elle a un retour nul), vous pouvez le faire:

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

Ou, vous pouvez appeler la vraie méthode pour toutes les méthodes de cette classe, en procédant comme suit:

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

En ajoutant à ce que @sateesh a dit, lorsque vous voulez simplement vous moquer d'une méthode void afin d'empêcher le test de l'appeler, vous pouvez utiliser un Spy de cette façon:

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

Lorsque vous souhaitez exécuter votre test, veillez à appeler la méthode à tester sur l'objet spy et non sur l'objet world. Par exemple:

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

Tout d’abord: vous devriez toujours importer mockito static, afin que le code soit beaucoup plus lisible (et intuitif):

import static org.mockito.Mockito.*;

Pour les moqueries partielles tout en conservant la fonctionnalité d'origine sur le reste, Mockito propose "Spy".

Vous pouvez l'utiliser comme suit:

private World world = spy(World.class);

Pour éliminer une méthode de l'exécution, vous pouvez utiliser quelque chose comme ceci:

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

pour donner un comportement personnalisé à une méthode, utilisez "when" avec un "thenReturn":

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

Pour plus d'exemples, veuillez trouver les exemples de mockito dans la doc.

25
fl0w

Comment se moquer des méthodes void avec mockito - il y a deux options:

  1. doAnswer - Si nous voulons que notre méthode void fictive fasse quelque chose (simule le comportement malgré le fait d'être void).
  2. doThrow - Ensuite, il y a Mockito.doThrow() si vous voulez lever une exception à partir de la méthode void mocked.

Voici un exemple d'utilisation (ce n'est pas un cas d'utilisation idéal, mais je voulais simplement illustrer l'utilisation de base).

@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]");

}
}

Vous pourriez trouver plus de détails sur la façon de simuler et tester void méthodes avec Mockito dans mon post Comment se moquer de Mockito (Un guide complet avec des exemples)

19

Ajouter une autre réponse au peloton (sans jeu de mots) ...

Vous devez appeler la méthode doAnswer si vous ne pouvez\pas utiliser Spy's. Cependant, vous n'avez pas nécessairement besoin de lancer votre propre réponse . Il existe plusieurs implémentations par défaut. Notamment, CallsRealMethods .

En pratique, cela ressemble à quelque chose comme ça:

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

Ou:

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

Dans Java 8, ceci peut être rendu un peu plus propre, en supposant que vous ayez une importation statique pour org.mockito.Mockito.doAnswer:

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

Le return null; est important et sans lui la compilation échouera avec des erreurs assez obscures car il ne pourra pas trouver de remplacement approprié pour doAnswer.

Par exemple, un ExecutorService qui exécute immédiatement n'importe quel Runnable transmis à execute() peut être implémenté en utilisant:

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

Je pense que vos problèmes sont dus à votre structure de test. J'ai trouvé difficile de mélanger le moqueur avec la méthode traditionnelle d'implémentation d'interfaces dans la classe de test (comme vous l'avez fait ici).

Si vous implémentez l'écouteur en tant que simulacre, vous pouvez alors vérifier l'interaction.

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

Cela devrait vous convaincre que le "Monde" fait ce qu'il faut.

5
ashley

@ashley: travaille pour moi

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