web-dev-qa-db-fra.com

Mockito donne UnfinishedVerificationException quand il semble bien

Mockito semble lancer une UnfinishedVerificationException lorsque je pense avoir tout fait correctement. Voici mon cas de test partiel:

HttpServletRequest req = mock(HttpServletRequest.class);
when(req.getHeader("Authorization")).thenReturn("foo");

HttpServletResponse res = mock(HttpServletResponse.class);

classUnderTest.doMethod(req, res); // Use the mock

verify(res, never());
verify(req).setAttribute(anyString(), anyObject());

Et voici la classe partielle et la méthode:

class ClassUnderTest extends AnotherClass {
    @Override
    public String doMethod(ServletRequest req, ServletRequest res) {
        // etc.
        return "someString";
    }
}

Ignorant le fait que vous ne devriez jamais vous moquer des interfaces que vous ne possédez pas, pourquoi Mockito m'envoie-t-il le message suivant?

org.mockito.exceptions.misusing.UnfinishedVerificationException: 
Missing method call for verify(mock) here:
-> at (redacted)

Example of correct verification:
    verify(mock).doSomething()

Also, this error might show up because you verify either of: final/private/equals()/hashCode() methods.
Those methods *cannot* be stubbed/verified.

at [test method name and class redacted]
at Sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at Sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.Java:57)
at Sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.Java:43)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.Java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.Java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.Java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.Java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.Java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.Java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.Java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.Java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.Java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.Java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.Java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.Java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.Java:309)
at org.mockito.internal.runners.JUnit45AndHigherRunnerImpl.run(JUnit45AndHigherRunnerImpl.Java:37)
at org.mockito.runners.MockitoJUnitRunner.run(MockitoJUnitRunner.Java:62)
at org.junit.runner.JUnitCore.run(JUnitCore.Java:160)
... etc
28
Jonathan

Je viens de découvrir cela moi-même et cela m'a causé beaucoup de confusion.

Comme David l'a mentionné ci-dessus, Mockito signale des erreurs dans l'appel de méthode next Mockito qui peuvent ne pas appartenir à la même méthode de test. Bien que le message d'exception contienne une référence à l'endroit où l'erreur s'est produite, les tests incorrects échouent et sont contre-productifs pour le processus de test. Et plus les tests sont simples, plus une erreur risque de se présenter lors du prochain test!

Voici une solution simple qui garantira que les erreurs apparaissent dans la méthode de test correcte:

@After
public void validate() {
    validateMockitoUsage();
}

De la documentation Mockito ici :

Mockito lève des exceptions si vous en abusez pour savoir si votre les tests sont écrits correctement. Le truc c'est que Mockito fait le validation la prochaine fois que vous utiliserez le framework (par exemple, la prochaine fois que vous vérifierez, stub, call mock, etc.). Mais même si l'exception peut être levée dans le test suivant, le message d'exception contient une pile navigable oligo-élément avec localisation du défaut. Par conséquent, vous pouvez cliquer sur et trouvez l'endroit où Mockito a été mal utilisé.

Parfois cependant, vous pourriez vouloir valider explicitement l'utilisation du framework. Par exemple, l'un des les utilisateurs voulaient mettre validateMockitoUsage () dans sa méthode @After afin que qu'il sait immédiatement quand il a mal utilisé Mockito. Sans cela, il aurait su à ce sujet pas plus tôt que la prochaine fois qu'il a utilisé le cadre. Un autre avantage d'avoir validateMockitoUsage () dans @After est que le coureur jUnit échouera toujours dans la méthode de test avec défaut alors que la validation "prochaine fois" ordinaire pourrait échouer au test suivant méthode. Mais même si JUnit peut indiquer que le prochain test est rouge, ne le faites pas inquiétez-vous et cliquez simplement sur l’élément de trace de pile navigable dans le fichier message d’exception pour localiser instantanément le lieu où vous avez abusé Mockito.

48
SteveMellross

Cela peut aussi être causé si vous essayez de verify une méthode qui attend des arguments primitifs avec any():

Par exemple, si notre méthode a cette signature:

method(long l, String s);

Et vous essayez de le vérifier comme ça, il échouera avec le message susmentionné:

verify(service).method(any(), anyString());

Changez-le en anyLong() et cela fonctionnera:

verify(service).method(anyLong(), anyString());
33
Babken Vardanyan

Je recevais cette même erreur en raison de l'utilisation de any() avec un paramètre boolean, alors qu'apparemment il devait être anyBoolean().

2
Matt Klein

Pour moi, le problème s’est avéré être une déclaration de bean manquante dans le contexte de test XML. C'était pour une classe d'aspect personnalisée utilisée par une autre classe, dont une instance est un paramètre pour le constructeur de la classe qui est le paramètre pour l'échec de l'appel verify (). J'ai donc ajouté la déclaration de haricot au contexte XML et tout a bien fonctionné par la suite. 

1
user7431997

Je ne sais pas d'où vient votre "classUnderTest", mais assurez-vous que c'est moqué , pas un vrai . J'ai le même problème pour mon cas de test ci-dessous:

MyAgent rpc = new MyAgent("myNodeName");
...
rpc.doSomething();
...
PowerMockito.verifyPrivate(rpc).invoke("initPowerSwitch");
PowerMockito.verifyPrivate(rpc).invoke("init", "192.168.0.23", "b2", 3);

Mais il a disparu pour le cas de test suivant:

MyAgent rpc = PowerMockito.spy(new MyAgent("myNodeName"));
...
rpc.doSomething();
...
PowerMockito.verifyPrivate(rpc).invoke("initPowerSwitch");
PowerMockito.verifyPrivate(rpc).invoke("init", "192.168.0.23", "b2", 3);

Attention, l'objet rpc doit être moqué par PowerMockito.spy (...) .

0
Sam

Si vous essayez de vérifier une méthode privée ou package-private avec Mockito.verify, vous obtiendrez cette erreur.

Si vous ne souhaitez pas utiliser PowerMockito, vous pouvez définir votre méthode comme protégée et je vous conseille d'ajouter le tag @VisibleForTesting

Avant:

void doSomething() {
   //Some behaviour
}

Après :

@VisibleForTesting
protected void doSomething() {
   //Some behaviour
}
0
Ben-J

Avec Junit 5, vous pouvez ajouter ce qui suit pour afficher des exceptions Mockito plus significatives dans la console. 

@AfterEach
public void validate() {
    validateMockitoUsage()
}

Voir aussi cette réponse: https://stackoverflow.com/a/22550055/8073652

0
s1m0nw1

J'ai eu un problème similaire, j'ai trouvé un moyen de résoudre ce problème. Les objets fictifs que vous avez vérifiés n'ont pas encore été réinitialisés. Vous devez donc les réinitialiser. Vous pouvez réinitialiser (fictif) avant que votre scénario de test fonctionne, cela peut être utile.

0
Van Ke

J'ai eu une exception similaire avec la classe MyRepository

org.mockito.exceptions.misusing.UnfinishedVerificationException: Appel de méthode manquant pour vérifier (maquette) ici: -> sur MyRepository $$ FastClassBySpringCGLIB $$ de8d8358.invoke ()

Exemple de vérification correcte:

verify(mock).doSomething()

Le problème a été résolu lorsque j'ai créé une interface pour MyRepository et une interface fictive, mais pas d'implémentation . Il semble que spring crée des proxy CGLIB et conduit à une exception UnfinishedVerificationException.

0
Geniy