Come usare ArgumentCaptor per lo stub?


161

In Mockito documentazione e javadocs si dice

Si consiglia di utilizzare ArgumentCaptor con verifica ma non con stub.

ma non capisco come ArgumentCaptor possa essere usato per lo stub. Qualcuno può spiegare la suddetta affermazione e mostrare come ArgumentCaptor può essere utilizzato per lo stub o fornire un link che mostra come può essere fatto?


1
Spiegazione super breve e piacevole qui: dzone.com/articles/…
Benj,

Risposte:


271

Supponendo il seguente metodo per testare:

public boolean doSomething(SomeClass arg);

Documentazione Mockito dice che si dovrebbe non utilizzare rapitore in questo modo:

when(someObject.doSomething(argumentCaptor.capture())).thenReturn(true);
assertThat(argumentCaptor.getValue(), equalTo(expected));

Perché puoi semplicemente usare il matcher durante lo stub:

when(someObject.doSomething(eq(expected))).thenReturn(true);

Ma la verifica è una storia diversa. Se il test deve garantire che questo metodo sia stato chiamato con un argomento specifico, utilizzare ArgumentCaptore questo è il caso per cui è stato progettato:

ArgumentCaptor<SomeClass> argumentCaptor = ArgumentCaptor.forClass(SomeClass.class);
verify(someObject).doSomething(argumentCaptor.capture());
assertThat(argumentCaptor.getValue(), equalTo(expected));

Grazie per la risposta. Ho una domanda. Nel terzo blocco di codice sappiamo che true viene restituito solo quando l' atteso viene passato a doSomething. Ma quando viene restituito true nel secondo blocco di codice? Oppure someObject restituisce sempre true per someMethod in quel caso?
Non posso dirlo il

Hm, credo che volevi dire "Ma quando viene restituito true nel terzo blocco di codice?". Nel terzo blocco di codice non ci interessa il valore restituito e lasciamo che sia quello predefinito. Per il booleano lo è false, no true.
Rorick,

No, ho considerato tutti i blocchi di sfondo grigio come blocchi di codice. Compreso il primo liner. Mi riferivo alla riga quando (someObject.doSomething (argumentCaptor.capture ())). ThenReturn (true);
Non posso dirlo il

Mi dispiace. Sì, in questo caso true verrà restituito sempre.
Rorick,

3
non sono sicuro che il motivo per "non usare con lo stub" sia un semplice motivo. i matcher non ci danno l'argomento atteso (solo il tipo) e portano a stare bene con i test che passano nonostante argomenti che potrebbero essere sbagliati.
dtc,

0

La linea

when(someObject.doSomething(argumentCaptor.capture())).thenReturn(true);

farebbe lo stesso di

when(someObject.doSomething(Matchers.any())).thenReturn(true);

Quindi, usando argomentoCaptor.capture () quando lo stub non ha valore aggiunto. L'uso di Matchers.any () mostra meglio ciò che accade realmente e quindi è meglio per la leggibilità. Con argumentCaptor.capture (), non puoi leggere quali argomenti sono realmente abbinati. E invece di usare any (), puoi usare matcher più specifici quando hai più informazioni (classe dell'argomento atteso), per migliorare il tuo test.

E un altro problema: se si utilizza argomentoCaptor.capture () durante lo stubbing, non è chiaro quanti valori dovresti aspettarti di essere catturato dopo la verifica. Vogliamo acquisire un valore durante la verifica, non durante lo stub perché a quel punto non c'è ancora alcun valore da acquisire. Quindi, cosa catturano i metodi di cattura degli argomenti durante la fase di stub? o non cattura nulla? Non ho la risposta a questa domanda. Lo considero un comportamento indefinito e non voglio usare un comportamento indefinito.


0

Ipoteticamente, se la ricerca ti ha portato a questa domanda, probabilmente lo desideri:

doReturn(someReturn).when(someObject).doSomething(argThat(argument -> argument.getName().equals("Bob")));

Perché? Perché come me apprezzi il tempo e non implementerai .equalssolo per il singolo scenario di test.

E il 99% dei test cade a pezzi con null restituito da Mock e con un design ragionevole eviteresti di restituire nulla tutti i costi, utilizzare Optionalo passare a Kotlin. Ciò implica che verifynon è necessario utilizzarlo spesso e ArgumentCaptors è troppo noioso per scrivere.

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.