L'utilisation de PowerMockito.whenNew () n'est pas moquée et la méthode originale est appelée

100

J'ai un code un peu comme celui-ci ci-dessous:

Class A {
  public boolean myMethod(someargs) {
    MyQueryClass query = new MyQueryClass();
    Long id = query.getNextId();
    // some more code
  }
}
Class MyQueryClass     {
  ....
  public Long getNextId() {
    //lot of DB code, execute some DB query
    return id;
  }
}

Maintenant j'écris un test pour A.myMethod(someargs). Je veux ignorer la méthode réelle query.getNextId()et renvoyer à la place une valeur de stub. En gros, je veux me moquer MyQueryClass.

Donc, dans mon cas de test, j'ai utilisé:

MyQueryClass query = PowerMockito.mock(MyQueryClass.class);
PowerMockito.whenNew(MyQueryClass.class).withNoArguments().thenReturn(query);
when(query.getNextId()).thenReturn(1000000L);

boolean b = A.getInstance().myMethod(args);

//asserts

J'ai utilisé @RunWith(PowerMockRunner.class)et @PrepareForTest({MyQueryClass.class})au début de mon cours de test.

Mais quand je débogue le test, il appelle toujours la vraie méthode getNextId()de la MyQueryClassclasse.

Qu'est-ce que j'oublie ici? Quelqu'un peut-il m'aider car je suis nouveau sur Mockito et PowerMockito.

user3942446
la source

Réponses:

220

Vous devez placer la classe où le constructeur est appelé dans l' @PrepareForTestannotation au lieu de la classe en cours de construction - voir Construction simulée de nouveaux objets .

Dans ton cas:

@PrepareForTest(MyQueryClass.class)

@PrepareForTest(A.class)

Plus général:

@PrepareForTest(NewInstanceClass.class)

@PrepareForTest(ClassThatCreatesTheNewInstance.class)

TrueDub
la source
1
Merci beaucoup. Cela fonctionnait maintenant après avoir inclus la classe actuelle, par exemple A dans le @PrepareForTest.
user3942446
2
Je passe du temps pour ça aussi. Merci @TrueDub. Parce que la référence est obsolète. Je viens de le mettre à jour. github.com/jayway/powermock/wiki/MockConstructor Cela dit: Utilisez l'annotation @PrepareForTest (ClassThatCreatesTheNewInstance.class) au niveau de la classe du scénario de test.
Victor Choy le
4
J'ai le même problème, mais cette solution ne fonctionne pas pour moi
dexter
3
Cette solution ne fonctionnera tout simplement pas si vous utilisez eclemma pour la couverture de code. L'ajout de la classe testée à @PrepareForTest entraînera une couverture de 0% pour cette classe
ACV
2
La solution fonctionnera - le test s'exécute correctement. De toute évidence, l'éclemme n'est pas équipé pour faire face à PowerMockito. La couverture du code ne fait pas partie de cette question.
TrueDub
3

Comme @TrueDub l'a mentionné dans sa réponse acceptée, vous devez ajouter la classe où le constructeur est appelé au @PrepareForTest.

Cependant, si vous faites cela, la couverture pour cette classe telle que rapportée par eclemma et Sonar sera nulle pour cette classe

Wiki Powermockito

Nous allons remplacer Javassist par ByteBuddy (# 727) et cela devrait aider à résoudre ce vieux problème. Mais pour le moment, il n'y a AUCUN MOYEN D'UTILISER PowerMock avec l'instrumentation JaCoCo On-the-fly. Et aucune solution de contournement pour obtenir la couverture de code dans l'IDE.

La solution ici serait donc de refactoriser le code réel pour utiliser une fabrique statique qui retournerait une instance de cette classe, puis la simulerait statiquement.

ACV
la source
Je suis d'accord avec votre commentaire.
Lathy
Ce n'est pas un problème dans Intellij cependant.
ACV
0

Peut-être pouvez-vous simplement utiliser

Mockito.doReturn(value).when(xxx)
jiajianchen
la source