@RunWith (MockitoJUnitRunner.class) vs MockitoAnnotations.initMocks (questo)


118

Durante la scrittura di un nuovo test jUnit4, mi chiedo se utilizzare @RunWith (MockitoJUnitRunner.class) o MockitoAnnotations.initMocks (questo) .

Ho creato un nuovo test e la procedura guidata ha generato automaticamente un test con il Runner. Javadocs per MockitoJUnitRunner afferma quanto segue:

Compatibile con JUnit 4.4 e versioni successive, questo runner aggiunge il seguente comportamento:

Inizializza i mock annotati con Mock, in modo che l'utilizzo esplicito di MockitoAnnotations.initMocks (Object) non sia necessario. I mock vengono inizializzati prima di ogni metodo di test. convalida l'utilizzo del framework dopo ogni metodo di test.

Non mi è chiaro se l'utilizzo del Runner abbia qualche vantaggio rispetto al metodo initMocks () che ho usato in passato.

Qualsiasi pensiero o collegamento sarebbe apprezzato!

Risposte:


147

MockitoJUnitRunnerti offre la convalida automatica dell'utilizzo del framework, nonché un file initMocks().

Vale davvero la pena avere la convalida automatica dell'utilizzo del framework. Ti offre rapporti migliori se commetti uno di questi errori.

  • Chiami il whenmetodo statico , ma non completare lo stubbing con una corrispondenza thenReturn, thenThrowo then. (Errore 1 nel codice sottostante)

  • Chiami verifyun mock, ma dimentichi di fornire la chiamata al metodo che stai cercando di verificare. (Errore 2 nel codice sottostante)

  • Si chiama il whenmetodo dopo doReturn, doThrowo doAnswere passa un finto, ma dimentica di fornire il metodo che si sta tentando di stub. (Errore 3 nel codice sottostante)

Se non si dispone della convalida dell'utilizzo del framework, questi errori non vengono riportati fino alla chiamata seguente a un metodo Mockito. Potrebbe essere

  • nello stesso metodo di prova (come l'errore 1 di seguito),
  • nel metodo di test successivo (come l'errore 2 di seguito),
  • nella prossima classe di prova.

Se si verificano nell'ultimo test eseguito (come l'errore 3 di seguito), non verranno segnalati affatto.

Ecco come potrebbe apparire ciascuno di questi tipi di errori. Supponiamo qui che JUnit esegua questi test nell'ordine in cui sono elencati qui.

@Test
public void test1() {

    // ERROR 1
    // This compiles and runs, but it's an invalid use of the framework because 
    // Mockito is still waiting to find out what it should do when myMethod is called.
    // But Mockito can't report it yet, because the call to thenReturn might 
    // be yet to happen.
    when(myMock.method1());

    doSomeTestingStuff();

    // ERROR 1 is reported on the following line, even though it's not the line with
    // the error.
    verify(myMock).method2();

}

@Test
public void test2() {

    doSomeTestingStuff();

    // ERROR 2
    // This compiles and runs, but it's an invalid use of the framework because
    // Mockito doesn't know what method call to verify.  But Mockito can't report 
    // it yet, because the call to the method that's being verified might 
    // be yet to happen.
    verify(myMock);
}

@Test
public void test3() {

    // ERROR 2 is reported on the following line, even though it's not even in 
    // the same test as the error.
    doReturn("Hello").when(myMock).method1();


    // ERROR 3
    // This compiles and runs, but it's an invalid use of the framework because
    // Mockito doesn't know what method call is being stubbed.  But Mockito can't 
    // report it yet, because the call to the method that's being stubbed might 
    // be yet to happen.

    doReturn("World").when(myMock);

    doSomeTestingStuff(); 

    //  ERROR 3 is never reported, because there are no more Mockito calls. 
}

Quando ho scritto per la prima volta questa risposta più di cinque anni fa, ho scritto

Quindi consiglierei l'uso di quando MockitoJUnitRunnerpossibile. Tuttavia, come ha correttamente sottolineato Tomasz Nurkiewicz, non puoi usarlo se hai bisogno di un altro runner JUnit, come quello Spring.

La mia raccomandazione è ora cambiata. Il team di Mockito ha aggiunto una nuova funzionalità da quando ho scritto per la prima volta questa risposta. È una regola JUnit, che svolge esattamente la stessa funzione di MockitoJUnitRunner. Ma è meglio, perché non preclude l'utilizzo di altri corridori.

Includere

@Rule 
public MockitoRule rule = MockitoJUnit.rule();

nella tua classe di prova. Questo inizializza i mock e automatizza la validazione del framework; proprio come MockitoJUnitRunnerfa. Ma ora puoi usare anche SpringJUnit4ClassRunnerqualsiasi altro JUnitRunner. Da Mockito 2.1.0 in poi, ci sono opzioni aggiuntive che controllano esattamente il tipo di problemi che vengono segnalati.


non posso assolutamente dire che siano la stessa cosa. in un caso di test, la configurazione del runner junit fallisce per me e non inietta correttamente i miei mock a meno che non esegua l'installazione di initMocks
dtc

Stiamo usando testng 6.8.8 + mockito 1.10.19 e, ovviamente, non possiamo usare MockitoJUnitRunner, ma il framework di validazione funziona ancora! E funziona esattamente come @David Wallace. Qualcuno può spiegare? È perché abbiamo ancora @ Before * callback e MockitoAnnotations.initMocks (this)?
yuranos

@ yuranos87 Sembra qualcosa che dovresti porre come nuova domanda. Non dimenticare di includere il tuo codice quando lo fai - è un po 'inutile chiedere "perché questo codice fa XYZ" se non mostri il codice.
Dawood ibn Kareem

1
l'utilizzo della soluzione TestRunner supera di gran lunga la @Rule
Regola

1
@alexandroid Il mio miglior suggerimento è di scrivere la tua risposta, usando @ExtendWith. Non è davvero qualcosa che conosco. La cosa grandiosa di Stack Overflow è che su una domanda come questa, puoi ottenere più risposte corrette.
Dawood ibn Kareem

24

L'uso di runner ti consente di salvare un po 'di codice (non è necessario un @Beforemetodo). D'altra parte a volte non è possibile usare un corridore, cioè quando ne stai già usando uno, come SpringJUnit4ClassRunner.

Questo è tutto. È solo una questione di preferenza.


2
Oltre alla riga initMocks (), il metodo @Before sarebbe ancora necessario per qualsiasi altra configurazione, giusto?
OceanBlue

2
@OceanBlue: Ovviamente se il tuo @Beforemetodo conteneva qualcosa tranne initMocks()che devi conservarlo dopo la migrazione a runner.
Tomasz Nurkiewicz

La risposta di David Wallace sulla convalida del framework risponde pienamente alla mia domanda, quindi l'ho accettata, ma +1 per aver sottolineato che questo runner non può essere utilizzato con un altro, come quello Spring. Grazie!
OceanBlue

1
Sto usando Spring Boot e posso dire che SpringJUnit4ClassRunnerinizializza automaticamente i mock per me. Però non so nulla della semplice primavera.
gustavohenke
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.