callback mockito e ottenere i valori degli argomenti


89

Non ho alcuna fortuna nel convincere Mockito a catturare i valori degli argomenti della funzione! Sto prendendo in giro un indice del motore di ricerca e invece di costruire un indice, sto solo usando un hash.

// 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))

Non posso usare argomenti arbitrari perché sto testando i risultati delle query (cioè quali documenti restituiscono). Allo stesso modo, non voglio specificare un valore specifico per e avere una riga per ogni documento!

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

Ho esaminato la sezione dei callback nella pagina Using Mockito . Sfortunatamente, non è Java e non sono riuscito a far funzionare la mia interpretazione in Java.

EDIT (per chiarimenti): come faccio a convincere Mockito a catturare un argomento X e passarlo alla mia funzione? Voglio che il valore esatto (o ref) di X sia passato alla funzione.

Non voglio enumerare tutti i casi e l'argomento arbitrario non funzionerà perché sto testando risultati diversi per query diverse.

La pagina di Mockito dice

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

Non è java, e non so come tradurre in java o passare quello che è successo in una funzione.


Non sono sicuro di aver capito esattamente cosa sta fallendo per te. La tua chiamata a Mockito.when(reader.document(666)).thenReturn(document(fakeIndex(666))dovrebbe impostare l'oggetto fittizio per te. Cosa succede quando chiami reader.document(666)?
altamente caffeinated il

Il 666 funziona bene. Tuttavia, mi piacerebbe poter passare un numero specifico X e ottenere il risultato di fakeIndex (X). Ho un gran numero di potenziali documenti da testare per le query e non voglio inserirli tutti.
nflacco

Risposte:


104

Non ho mai usato Mockito, ma voglio imparare, quindi ecco qui. Se qualcuno meno incapace di me risponde, prova prima la sua risposta!

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

2
Ho appena notato il collegamento sul lato destro a Mockito: Come fare in modo che un metodo restituisca un argomento che gli è stato passato . Sembra che io sia vicino, se non esatto.
Ed Staub

forte reputazione degli utenti (666) alla correlazione originale delle domande! Ha funzionato molto bene. L'unica modifica che ho apportato per ottenere la compilazione delle cose è stata resa pubblica davanti a Object answer (invocazione InvocationOnMock) ....
nflacco

54

Dai un'occhiata a 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());
    }
  });

3
Wow, non sapevo che potessi usare la ArgumentCaptors per stubbing. C'è però un grande avvertimento a riguardo in quel link. Procedi con cautela.
einnocent

3
Sì, hai ragione. I catturatori dovrebbero essere usati solo con verifiche.
qualidafial

41

Potresti voler usare verify () in combinazione con ArgumentCaptor per garantire l'esecuzione nel test e ArgumentCaptor per valutare gli argomenti:

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

Il valore dell'argomento è ovviamente accessibile tramite l'argomento.getValue () per ulteriori manipolazioni / controlli o qualsiasi altra cosa tu voglia fare.


2
migliore risposta: diretta, facile da capire
Radu Cugut

Non risponde alla domanda. La domanda riguarda Mockito.when e non verifica.
seBaka28

@ seBaka28 la migliore soluzione per ottenere argomenti è un captatore di argomenti. Si consiglia vivamente di utilizzare ArgumentCaptor con verifica dagli autori di Mockito, quindi ho voluto dare una risposta completa in prospettiva. se per te stesso scegli di non usarli, è una tua scelta, ma non è consigliato. EDIT: Non vedo come questo giustifichi un voto negativo, ma questa è anche la tua scelta da fare.
fl0w

1
Perché non risponde alla domanda. Sì, ArgumentCaptor è ottimo quando vuoi catturare l'argomento, ma non puoi usarlo insieme a quando (...). ThenReturn () che è ciò che OP sta cercando di fare: in base a un determinato parametro, un servizio deriso dovrebbe restituire un oggetto specifico.
seBaka28

1
@YuraHoy che è un messaggio di errore standard quando usi la verifica e l'oggetto o il metodo viene chiamato più spesso di quanto hai detto di aspettarti. È possibile modificare il conteggio delle aspettative aggiungendo l'argomento times (n) come segue: verifica (reader, times (5)) - questo si aspetterebbe 5 interazioni. Per riferimento, vedere: baeldung.com/mockito-verify
fl0w

14

Con Java 8, potrebbe essere qualcosa del genere:

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

Suppongo che documentsia una mappa.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.