Mockito: Essayer d'espionner méthode appelle la méthode originale
J'utilise Mockito 1.9.0. Je veux simuler le comportement d'une méthode unique d'une classe de test JUnit, j'ai donc
final MyClass myClassSpy = Mockito.spy(myInstance);
Mockito.when(myClassSpy.method1()).thenReturn(myResults);
le problème est, dans la deuxième ligne, myClassSpy.method1()
est effectivement appelé, résultant en une exception. La seule raison pour laquelle j'utilise Mock est que plus tard, à chaque fois que myClassSpy.method1()
est appelé, la méthode réelle ne sera pas appelée et l'objet myResults
sera retourné.
MyClass
est une interface et myInstance
est une mise en œuvre de cela, si cela importe.
Que dois-je faire pour corriger ce espionnage de comportement?
7 réponses
Permettez-moi de citer la documentation officielle :
gotcha Important sur l'espionnage des objets réels!
parfois, il est impossible d'utiliser quand(objet) pour les espions. Exemple:
List list = new LinkedList();
List spy = spy(list);
// Impossible: real method is called so spy.get(0) throws IndexOutOfBoundsException (the list is yet empty)
when(spy.get(0)).thenReturn("foo");
// You have to use doReturn() for stubbing
doReturn("foo").when(spy).get(0);
Dans votre cas, il va quelque chose comme:
doReturn(resulstIWant).when(myClassSpy).method1();
mon cas était différent de la réponse acceptée. J'essayais de me moquer d'une méthode paquet-privé pour une instance qui ne vivait pas dans ce paquet
package common;
public class Animal {
void packageProtected();
}
package instances;
class Dog extends Animal { }
et les classes d'essai
package common;
public abstract class AnimalTest<T extends Animal> {
@Before
setup(){
doNothing().when(getInstance()).packageProtected();
}
abstract T getInstance();
}
package instances;
class DogTest extends AnimalTest<Dog> {
Dog getInstance(){
return spy(new Dog());
}
@Test
public void myTest(){}
}
la compilation est correcte, mais quand elle essaye de configurer le test, elle invoque la méthode réelle à la place.
déclarant la méthode protégé ou public fixe problème, tho ce n'est pas une solution propre.
la réponse de Tomasz Nurkiewicz semble ne pas raconter toute l'histoire!
NB Mockito version: 1.10.19.
je suis très Mockito newb, donc je ne peux pas expliquer le comportement suivant: s'il ya un expert là-bas qui peut améliorer cette réponse, s'il vous plaît se sentir libre.
la méthode en question ici, getContentStringValue
, est pas final
et pas static
.
Cette ligne ne appel de la méthode originale getContentStringValue
:
doReturn( "dummy" ).when( im ).getContentStringValue( anyInt(), isA( ScoreDoc.class ));
Cette ligne n'est pas appel de la méthode originale getContentStringValue
:
doReturn( "dummy" ).when( im ).getContentStringValue( anyInt(), any( ScoreDoc.class ));
Pour des raisons que je ne peux pas répondre, à l'aide de isA()
les causes de la destinée (?) "n'appelez pas la méthode" le comportement du doReturn
à l'échec.
regardons le signatures de méthode impliquées ici: elles sont toutes les deux static
méthodes de Matchers
. Tous les deux sont dits par le Javadoc pour retourner null
, qui est un peu difficile d'obtenir votre tête autour dans lui-même. Probablement l'objet Class
passé comme paramètre est examiné mais le résultat soit jamais calculé ou écarté. Étant donné que null
peut représenter n'importe quelle classe et que vous espérez que la méthode moquée ne sera pas appelée, les signatures de isA( ... )
et any( ... )
juste retour null
plutôt que d'un paramètre générique* <T>
?
de toute façon:
public static <T> T isA(java.lang.Class<T> clazz)
public static <T> T any(java.lang.Class<T> clazz)
la documentation de L'API ne donne aucun indice à ce sujet. Il semble également dire que la nécessité d'un tel comportement "ne pas appeler la méthode" est "très rare". Personnellement j'utilise cette technique tout le temps : typiquement je trouve que la moquerie implique quelques lignes qui" mettent le décor"... suivie par l'appel d'une méthode qui ensuite "joue" la scène dans le contexte simulé que vous avez mis en scène... et pendant que vous installez le décor et les accessoires, la dernière chose que vous voulez est que les acteurs entrent sur scène à gauche et commencent à jouer leur coeur...
mais c'est bien au-delà de mon niveau de rémunération... J'invite les grands prêtres Mockito à m'expliquer...
* "paramètre générique" le bon terme?
dans mon cas, en utilisant Mockito 2.0, j'ai dû changer tous les paramètres any() En nullable() afin de couper l'appel réel.
j'ai trouvé une autre raison pour que spy appelle la méthode originale.
Quelqu'un a eu l'idée de se moquer d'une classe final
, et a trouvé environ MockMaker
:
comme cela fonctionne différemment de notre mécanisme actuel et que celui-ci a des limites différentes et que nous voulons recueillir l'expérience et les commentaires des utilisateurs, cette fonctionnalité a dû être explicitement activée pour être disponible ; il peut être fait via le mécanisme d'extension mockito par création du fichier
src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
contenant une seule ligne:mock-maker-inline
après que j'ai fusionné et apporté ce fichier à ma machine, mes tests ont échoué.
j'ai juste eu à enlever la ligne (ou le fichier), et spy()
travaillé.
Une façon de s'assurer d'une méthode d'une classe n'est pas appelé à remplacer la méthode avec un mannequin.
WebFormCreatorActivity activity = spy(new WebFormCreatorActivity(clientFactory) {//spy(new WebFormCreatorActivity(clientFactory));
@Override
public void select(TreeItem i) {
log.debug("SELECT");
};
});
un autre scénario possible qui pourrait causer des problèmes avec les espions est quand vous testez Spring beans (avec le cadre de test de ressort) ou quelque autre cadre qui est proxing vos objets pendant le test .
exemple
@Autowired
private MonitoringDocumentsRepository repository
void test(){
repository = Mockito.spy(repository)
Mockito.doReturn(docs1, docs2)
.when(repository).findMonitoringDocuments(Mockito.nullable(MonitoringDocumentSearchRequest.class));
}
dans le code ci-dessus à la fois le printemps et Mockito va essayer de proxy votre MonitoringDocumentsRepository objet, mais le printemps sera le premier, ce qui causera l'appel réel de findMonitoringDocuments method. Si nous déboguons notre code juste après avoir placé un espion sur un objet de dépôt, il ressemblera à ceci dans le débogueur:
repository = MonitoringDocumentsRepository$$EnhancerBySpringCGLIB$$MockitoMock$
@SpyBean à la rescousse
si à la place @Autowired
annotation nous utilisons @SpyBean
annotation, nous allons résoudre le problème ci-dessus, l'annotation SpyBean injectera aussi objet de dépôt, mais il sera tout d'abord remplacé par Mockito et ressemblera à ce débogueur intérieur
repository = MonitoringDocumentsRepository$$MockitoMock$$EnhancerBySpringCGLIB$
et voici le code:
@SpyBean
private MonitoringDocumentsRepository repository
void test(){
Mockito.doReturn(docs1, docs2)
.when(repository).findMonitoringDocuments(Mockito.nullable(MonitoringDocumentSearchRequest.class));
}