mockito rappels et obtention des valeurs d'argument

88

Je n'ai pas de chance pour que Mockito capture les valeurs des arguments de fonction! Je me moque d'un index de moteur de recherche et au lieu de créer un index, j'utilise simplement un hachage.

// Fake index for solr
Hashmap<Integer,Document> fakeIndex;

// Add a document 666 to the fakeIndex
SolrIndexReader reader = Mockito.mock(SolrIndexReader.class);

// Give the reader access to the fake index
Mockito.when(reader.document(666)).thenReturn(document(fakeIndex(666))

Je ne peux pas utiliser d'arguments arbitraires car je teste les résultats des requêtes (c'est-à-dire quels documents elles renvoient). De même, je ne veux pas spécifier une valeur spécifique pour et avoir une ligne pour chaque document!

Mockito.when(reader.document(0)).thenReturn(document(fakeIndex(0))
Mockito.when(reader.document(1)).thenReturn(document(fakeIndex(1))
....
Mockito.when(reader.document(n)).thenReturn(document(fakeIndex(n))

J'ai regardé la section des rappels sur la page Utilisation de Mockito . Malheureusement, ce n'est pas Java et je n'ai pas pu faire fonctionner ma propre interprétation de cela en Java.

EDIT (pour clarification): Comment obtenir Mockito pour capturer un argument X et le passer dans ma fonction? Je veux que la valeur exacte (ou ref) de X soit transmise à la fonction.

Je ne veux pas énumérer tous les cas, et l'argument arbitraire ne fonctionnera pas car je teste différents résultats pour différentes requêtes.

La page Mockito dit

val mockedList = mock[List[String]]
mockedList.get(anyInt) answers { i => "The parameter is " + i.toString } 

Ce n'est pas java, et je ne sais pas comment traduire en java ou transmettre tout ce qui s'est passé dans une fonction.

nflacco
la source
Je ne suis pas sûr de comprendre exactement ce qui échoue pour vous. Votre appel à Mockito.when(reader.document(666)).thenReturn(document(fakeIndex(666))devrait configurer l'objet simulé pour vous. Que se passe-t-il lorsque vous appelez reader.document(666)?
hautement caféiné le
Le 666 fonctionne très bien. Cependant, j'aimerais pouvoir passer un nombre spécifique X et obtenir le résultat de fakeIndex (X). J'ai un grand nombre de documents potentiels à tester pour les requêtes, et je ne veux pas les saisir tous.
nflacco

Réponses:

103

Je n'ai jamais utilisé Mockito, mais je veux apprendre, alors voilà. Si quelqu'un de moins ignorant que moi répond, essayez d'abord sa réponse!

Mockito.when(reader.document(anyInt())).thenAnswer(new Answer() {
 public Object answer(InvocationOnMock invocation) {
     Object[] args = invocation.getArguments();
     Object mock = invocation.getMock();
     return document(fakeIndex((int)(Integer)args[0]));
     }
 });
Ed Staub
la source
2
Je viens de remarquer le lien sur le côté droit vers Mockito: Comment faire en sorte qu'une méthode renvoie un argument qui lui a été passé . On dirait que je suis proche, sinon sur place.
Ed Staub le
forte réputation de l'utilisateur (666) à la corrélation des questions originales! Cela a très bien fonctionné. Seule la modification que j'ai apportée pour obtenir la compilation de trucs a été rendue publique devant la réponse d'objet (invocation InvocationOnMock) ....
nflacco
54

Découvrez ArgumentCaptors:

https://site.mockito.org/javadoc/current/org/mockito/ArgumentCaptor.html

ArgumentCaptor<Integer> argument = ArgumentCaptor.forClass(Integer.class);
Mockito.when(reader.document(argument.capture())).thenAnswer(
  new Answer() {
    Object answer(InvocationOnMock invocation) {
      return document(argument.getValue());
    }
  });
qualidafial
la source
3
Wow, je ne savais pas que vous pouviez utiliser ArgumentCaptors pour le stubbing. Il y a cependant un gros avertissement à ce sujet dans ce lien. Procéder avec prudence.
einnocent
3
Oui, tu as raison. Les capteurs ne doivent être utilisés qu'avec des vérifications.
qualidafial
41

Vous pouvez utiliser verify () en combinaison avec ArgumentCaptor pour assurer l'exécution du test et ArgumentCaptor pour évaluer les arguments:

ArgumentCaptor<Document> argument = ArgumentCaptor.forClass(Document.class);
verify(reader).document(argument.capture());
assertEquals(*expected value here*, argument.getValue());

La valeur de l'argument est évidemment accessible via l'argument.getValue () pour une manipulation / vérification supplémentaire ou tout ce que vous souhaitez faire.

fl0w
la source
2
meilleure réponse: simple, facile à comprendre
Radu Cugut
Ne répond pas à la question. La question concerne Mockito.when et ne vérifie pas.
seBaka28
@ seBaka28 la meilleure solution pour obtenir des arguments est un capteur d'arguments. Il est fortement conseillé aux auteurs de Mockito d'utiliser ArgumentCaptors avec verify, c'est pourquoi je voulais donner une réponse en perspective complète. si vous choisissez vous-même de ne pas les utiliser, c'est votre choix, mais ce n'est pas conseillé. EDIT: Je ne vois pas en quoi cela justifie un vote négatif, mais c'est aussi votre choix à faire.
fl0w
1
Parce qu'il ne répond pas à la question. Oui, ArgumentCaptor est génial lorsque vous voulez capturer l'argument, mais vous ne pouvez pas l'utiliser en conjonction avec when (...). ThenReturn () qui est ce que OP essaie de faire: Basé sur un certain paramètre, un service simulé est censé renvoyer un objet spécifique.
seBaka28
1
@YuraHoy qui est un message d'erreur standard lorsque vous utilisez verify et que l'objet ou la méthode est appelé plus souvent que ce que vous avez indiqué à vérifier. Vous pouvez modifier le décompte des attentes en ajoutant l'argument times (n) comme suit: verify (reader, times (5)) - cela attend 5 interactions. Pour référence, veuillez consulter: baeldung.com/mockito-verify
fl0w
13

Avec Java 8, cela pourrait être quelque chose comme ceci:

Mockito.when(reader.document(anyInt())).thenAnswer(
  (InvocationOnMock invocation) -> document(invocation.getArguments()[0]));

Je suppose que documentc'est une carte.

Jean-François Beauchef
la source