1214 votes

Comment simuler les méthodes void avec Mockito ?

Comment simuler des méthodes avec un retour de type void ?

J'ai implémenté un modèle d'observateur mais je ne peux pas le simuler avec Mockito parce que je ne sais pas comment.

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

Ma classe ressemble à ça :

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

Le système n'est pas déclenché par un simulacre.

Je veux montrer l'état du système mentionné ci-dessus. Et faire des assertions en fonction de ceux-ci.

14 votes

Attention, les méthodes void sur les mocks ne font rien par défaut !

2 votes

@Line, c'est ce que je cherchais. Cela semble évident après que vous l'ayez dit. Mais cela met en évidence un principe du mocking : vous n'avez besoin de faire un mocking des méthodes des classes mockées que pour leurs effets, comme une valeur de retour ou une exception. Je vous remercie !

1478voto

sateesh Points 7967

Jetez un coup d'œil au Mockito Documents de l'API . Comme le mentionne le document lié (point n° 12), vous pouvez utiliser n'importe quelle doThrow() , doAnswer() , doNothing() , doReturn() famille de méthodes du cadre Mockito pour simuler les méthodes void.

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

Si l'on suppose que vous cherchez à simuler la mise en place de l'émetteur. setState(String s) dans la classe World ci-dessous est le code utilise doAnswer pour simuler le 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());

10 votes

@qualidafial:Oui, je pense que la paramétrisation à Void serait mieux car elle transmet mieux que je ne suis pas intéressé par le type de retour. Je n'étais pas au courant de cette construction, merci de le signaler.

2 votes

DoThrow est #5 maintenant (aussi pour moi utilisant doThrow cela a corrigé le message "'void' type not allowed here", pour les adeptes...)

0 votes

@qualidafial : Je pense que le type de retour de l'appel Answer.answer n'est pas ce qui est renvoyé à la méthode originale, c'est ce qui est renvoyé à l'appel doAnswer, vraisemblablement si vous voulez faire autre chose avec cette valeur dans votre test.

138voto

MarcioB Points 93

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 vide) vous pouvez faire ceci :

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

Ou bien, vous pouvez appeler la vraie méthode pour toutes les méthodes de cette classe, en faisant ceci :

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

14 votes

C'est la vraie réponse juste ici. La méthode spy() fonctionne bien, mais elle est généralement réservée aux cas où vous voulez que l'objet fasse presque tout normalement.

1 votes

Qu'est-ce que cela signifie ? Est-ce que vous appelez réellement les méthodes ? Je n'ai pas vraiment utilisé mockito avant.

1 votes

Oui, l'objet fantaisie appellera les méthodes réelles. Si vous utilisez le @Mock, vous pouvez spécifier la même chose avec : @Mock(answer = Answers.CALLS_REAL_METHODS) pour obtenir les mêmes résultats.

61voto

ibrahimyilmaz Points 2498

La solution de ce problème est d'utiliser un spy Mockito.spy(...) au lieu d'un mock Mockito.mock(..) .

Spy nous permet de faire du mocking partiel. Mockito est bon dans ce domaine. Parce que vous avez une classe qui n'est pas complète, de cette façon vous pouvez simuler certains endroits nécessaires dans cette classe.

3 votes

J'ai atterri ici parce que j'ai eu un problème similaire (et, par coïncidence, je testais une interaction sujet/observateur). J'utilise déjà un espion mais je veux que la méthode 'SubjectChanged' fasse quelque chose de différent. Je pourrais utiliser `verify(observer).subjectChanged(subject) juste pour voir que la méthode a été appelée. Mais, pour une raison quelconque, je préfère surcharger la méthode. Pour cela, une combinaison de l'approche de Sateesh et de votre réponse ici était la voie à suivre...

37 votes

Non, faire cela n'aidera pas vraiment à mettre en place les méthodes void. L'astuce consiste à utiliser l'une des quatre méthodes statiques de Mockito listées dans la réponse de sateesh.

2 votes

@Gurnard pour votre question regardez ceci stackoverflow.com/questions/1087339/ .

18voto

javamonkey79 Points 6807

J'ajoute une autre réponse au lot (sans jeu de mots)...

Vous devez appeler la méthode doAnswer si vous ne pouvez pas \don Je ne veux pas utiliser d'espions. Cependant, vous n'avez pas nécessairement besoin de rouler votre propre Réponse : . Il existe plusieurs implémentations par défaut. Notamment, CallsRealMethods .

En pratique, cela ressemble à quelque chose comme ceci :

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

Ou :

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

7voto

ashley Points 111

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

Si vous implémentez l'écouteur comme un Mock, 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.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X