Differenza tra @Mock, @MockBean e Mockito.mock ()


147

Quando si creano test e si deridono le dipendenze, qual è la differenza tra questi tre approcci?

  1. @MockBean:

    @MockBean
    MyService myservice;
    
  2. @Mock:

    @Mock
    MyService myservice;
    
  3. Mockito.mock ()

    MyService myservice = Mockito.mock(MyService.class);

Risposte:


200

Libreria Plain Mockito

import org.mockito.Mock;
...
@Mock
MyService myservice;

e

import org.mockito.Mockito;
...
MyService myservice = Mockito.mock(MyService.class);

provengono dalla libreria Mockito e sono funzionalmente equivalenti.
Consentono di deridere una classe o un'interfaccia e di registrare e verificare comportamenti su di essa.

Il modo in cui si utilizza l'annotazione è più breve, quindi preferibile e spesso preferito.


Si noti che per abilitare le annotazioni Mockito durante le esecuzioni di test, MockitoAnnotations.initMocks(this)è necessario chiamare il metodo statico.
Per evitare effetti collaterali tra i test, si consiglia di farlo prima di ogni esecuzione del test:

@Before 
public void initMocks() {
    MockitoAnnotations.initMocks(this);
}

Un altro modo per abilitare le annotazioni Mockito è l'annotazione della classe test @RunWithspecificando MockitoJUnitRunnerciò che fa questo compito e anche altre cose utili:

@RunWith(org.mockito.runners.MockitoJUnitRunner.class)
public MyClassTest{...}

Libreria Spring Boot che avvolge la libreria Mockito

Questa è davvero una classe Spring Boot :

import org.springframework.boot.test.mock.mockito.MockBean;
...
@MockBean
MyService myservice;

La classe è inclusa nella spring-boot-testlibreria.

Permette di aggiungere beffe Mockito in una primavera ApplicationContext.
Se nel contesto esiste un bean compatibile con la classe dichiarata, lo sostituisce con il mock.
In caso contrario, aggiunge il mock nel contesto come bean.

Riferimento Javadoc:

Annotazione che può essere utilizzata per aggiungere simulazioni a Spring ApplicationContext.

...

Se un singolo bean esistente dello stesso tipo definito nel contesto verrà sostituito dal mock, se non viene definito alcun bean esistente, ne verrà aggiunto uno nuovo.


Quando usi Mockito classico / semplice e quando usi @MockBeanda Spring Boot?

I test unitari sono progettati per testare un componente in isolamento da altri componenti e anche i test unitari hanno un requisito: essere il più veloci possibile in termini di tempo di esecuzione poiché questi test possono essere eseguiti ogni giorno dozzina di volte sulle macchine sviluppatore.

Di conseguenza, ecco una semplice linea guida:

Mentre scrivi un test che non necessita di dipendenze dal contenitore Spring Boot, il classico / semplice Mockito è il modo da seguire: è veloce e favorisce l'isolamento del componente testato.
Se il test deve fare affidamento sul contenitore Spring Boot e si desidera anche aggiungere o deridere uno dei bean container: @MockBeanda Spring Boot è la soluzione.


Utilizzo tipico di Spring Boot @MockBean

Mentre scriviamo una classe di test annotata con @WebMvcTest(web test slice).

La documentazione di Spring Boot lo riassume molto bene:

Spesso @WebMvcTestsarà limitato a un singolo controller e utilizzato in combinazione con @MockBeanper fornire implementazioni simulate per i collaboratori richiesti.

Ecco un esempio:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@RunWith(SpringRunner.class)
@WebMvcTest(FooController.class)
public class FooControllerTest {

    @Autowired
    private MockMvc mvc;

    @MockBean
    private FooService fooServiceMock;

    @Test
    public void testExample() throws Exception {
         Foo mockedFoo = new Foo("one", "two");

         Mockito.when(fooServiceMock.get(1))
                .thenReturn(mockedFoo);

         mvc.perform(get("foos/1")
            .accept(MediaType.TEXT_PLAIN))
            .andExpect(status().isOk())
            .andExpect(content().string("one two"));
    }

}

4
L'uso di @MockBean creerà una copia del bean e lo inietterà in ApplicationContext? O il fagiolo deriso avrà tutti i suoi metodi come null? Se tutti i metodi sono nulli, posso cancellarli come posso fare usando @Mock?
Doug,

6
Come spiegato, l'utilizzo @MockBeansostituirà il bean nel contesto dell'applicazione se un bean che dichiara lo stesso tipo è già definito nella configurazione Spring. E l'iniezione viene eseguita nella classe in cui si dichiara @MockBean.I meccanismi DI funzionano in questo modo: si registra un oggetto nel contesto DI e quindi si può iniettare l'oggetto a cui si fa riferimento nel contesto Spring in una classe specifica. Non iniettare un oggetto nel contesto DI.
davidxxx,

13

Alla fine è facile da spiegare. Se guardi semplicemente nei javadocs delle annotazioni vedrai le differenze:

@Mock: ( org.mockito.Mock)

Segna un campo come un finto.

  • Consente la creazione di simulazioni stenografiche.
  • Riduce al minimo il codice di creazione fittizia ripetitiva.
  • Rende più leggibile la classe di test.
  • Rende più semplice la lettura dell'errore di verifica perché il nome del campo viene utilizzato per identificare la simulazione.

@MockBean: ( org.springframework.boot.test.mock.mockito.MockBean)

Annotazione che può essere utilizzata per aggiungere simulazioni a Spring ApplicationContext. Può essere utilizzato come annotazione a livello di classe o su campi in entrambe le @Configurationclassi o classi di test che sono @RunWithSpringRunner.

I mock possono essere registrati per tipo o per nome del bean. Qualsiasi bean singolo esistente dello stesso tipo definito nel contesto verrà sostituito dal mock, se non viene definito un bean esistente, ne verrà aggiunto uno nuovo.

Quando @MockBeanviene utilizzato su un campo, oltre ad essere registrato nel contesto dell'applicazione, il mock verrà anche iniettato nel campo.

Mockito.mock ()

È solo la rappresentazione di a @Mock.


5
Non dimentichiamo che @Mock richiede che MockitoRunner o initMocks vengano chiamati manualmente.
Florian Schaetz,

4
L'unica differenza tra @MockBeane @Mockche uno inietterà la derisione nel Spring ApplicationContexte l'altro no?
Doug,

3
@Doug Lo hai riassunto bene, ma bisogna ricordare che MockBean fa parte di Spring Boot
comiventor
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.