Mockito può stub un metodo senza tener conto dell'argomento?


302

Sto provando a testare un po 'di codice legacy, usando Mockito.

Voglio stub a FooDaoche viene utilizzato in produzione come segue:

foo = fooDao.getBar(new Bazoo());

Posso scrivere:

when(fooDao.getBar(new Bazoo())).thenReturn(myFoo);

Ma l'ovvio problema è che getBar()non viene mai chiamato con lo stesso Bazoooggetto per cui ho superato il metodo. (Maledici newquell'operatore!)

Mi piacerebbe se potessi stub il metodo in modo che ritorni myFooindipendentemente dall'argomento. In caso contrario, ascolterò altri suggerimenti, ma mi piacerebbe davvero evitare di modificare il codice di produzione fino a quando non vi sarà una copertura di test ragionevole.

Risposte:


456
when(
  fooDao.getBar(
    any(Bazoo.class)
  )
).thenReturn(myFoo);

oppure (per evitare null):

when(
  fooDao.getBar(
    (Bazoo)notNull()
  )
).thenReturn(myFoo);

Non dimenticare di importare i matcher (molti altri sono disponibili):

Per Mockito 2.1.0 e versioni successive:

import static org.mockito.ArgumentMatchers.*;

Per le versioni precedenti:

import static org.mockito.Matchers.*;

2
Adoro quando la risposta precede la fine del "accetta blocco delle risposte".
Eric Wilson,

10
C'è un notNull(Bazoo.class)tipo any(Bazoo.class)(forse non esisteva al momento di questa risposta)
Dandre Allison,

2
ho avuto una situazione un po 'particolare in cui ho potuto avere uno dei due possibili argomenti - Bazooo Cazooche sono entrambi sottoclassi di, diciamo, Azoo. perché Bazoodovevo tornare foo, ma Cazoodovevo tornare bar. in questa situazione la Matchers.any()soluzione proposta non funziona, tuttavia Matchers.isA()funziona perfettamente.
Tanvir,

3
org.mockito.Matchersora è deprecato - usa org.mockito.ArgumentMatchersinvece, cioè import static org.mockito.ArgumentMatchers.*(vedi documenti )
DontDivideByZero

when(myFoo.knowsWhatsUp()).thenReturn(myMoney);
6rchid

18

Usa così:

when(
  fooDao.getBar(
    Matchers.<Bazoo>any()
  )
).thenReturn(myFoo);

Prima di dover importare Mockito.Matchers


1
Questo è deprecato!
DrB,

15

http://site.mockito.org/mockito/docs/1.10.19/org/mockito/Matchers.html

anyObject() dovrebbe adattarsi alle tue esigenze.

Inoltre, puoi sempre considerare di implementare hashCode()e equals()per la Bazooclasse. Questo farebbe funzionare il tuo esempio di codice nel modo desiderato.


Concordo con il secondo suggerimento, ma sto ancora optando per non farlo per motivi non tecnici.
Eric Wilson,

1
La classe Matchers è obsoleta (vedi documenti - "Questa classe verrà probabilmente rimossa nella versione 3.0" )
Johannes Rabauer,

1

Un'altra opzione è quella di fare affidamento sul buon vecchio equalsmetodo di moda . Fintanto che l'argomento nella whenderisione è equalsl'argomento nel codice testato, allora Mockito corrisponderà alla derisione.

Ecco un esempio

public class MyPojo {

    public MyPojo( String someField ) {
        this.someField = someField;
    }

    private String someField;

    @Override
    public boolean equals( Object o ) {
        if ( this == o ) return true;
        if ( o == null || getClass() != o.getClass() ) return false;
        MyPojo myPojo = ( MyPojo ) o;
        return someField.equals( myPojo.someField );
    }

}

quindi, supponendo che tu sappia quale sarà il valore someField, puoi deriderlo in questo modo.

when(fooDao.getBar(new MyPojo(expectedSomeField))).thenReturn(myFoo);

pro: questo è più esplicito dei anymatcher. Come revisore del codice, tengo d'occhio anyil codice che gli sviluppatori junior scrivono, mentre dà un'occhiata alla logica del loro codice per generare l'oggetto appropriato che viene passato.

con: A volte il campo che viene passato all'oggetto è un ID casuale. In questo caso non è possibile creare facilmente l'oggetto argomento previsto nel codice di simulazione.

Un altro possibile approccio è usare l' Answeroggetto di Mockito che può essere usato con il whenmetodo. Answerconsente di intercettare la chiamata effettiva e ispezionare l'argomento di input e restituire un oggetto simulato. Nell'esempio che segue sto usando anyper intercettare qualsiasi richiesta al metodo che viene deriso. Ma poi nella Answerlambda, posso esaminare ulteriormente l'argomento Bazo ... forse per verificare che gli sia stato passato un documento di identità. Preferisco questo anyda solo in modo che almeno un po 'di ispezione venga fatta sull'argomento.

    Bar mockBar = //generate mock Bar.

    when(fooDao.getBar(any(Bazo.class))
    .thenAnswer(  ( InvocationOnMock invocationOnMock) -> {
        Bazo actualBazo = invocationOnMock.getArgument( 0 );

        //inspect the actualBazo here and thrw exception if it does not meet your testing requirements.
        return mockBar;
    } );

Quindi, per riassumere, mi piace fare affidamento su equals(dove l'argomento atteso e l'argomento reale dovrebbero essere uguali tra loro) e se uguale non è possibile (a causa della non essere in grado di prevedere lo stato dell'argomento effettivo), farò ricorso per Answercontrollare l'argomento.

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.