Différence entre @Mock, @MockBean et Mockito.mock ()


147

Lors de la création de tests et de la simulation de dépendances, quelle est la différence entre ces trois approches?

  1. @MockBean:

    @MockBean
    MyService myservice;
  2. @Moquer:

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

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

Réponses:


200

Bibliothèque Plain Mockito

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

et

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

proviennent de la bibliothèque Mockito et sont fonctionnellement équivalents.
Ils permettent de se moquer d'une classe ou d'une interface et d'enregistrer et de vérifier les comportements sur celle-ci.

La manière d'utiliser l'annotation est plus courte, donc préférable et souvent préférée.


Notez que pour activer les annotations Mockito lors des exécutions de test, la MockitoAnnotations.initMocks(this)méthode statique doit être appelée.
Pour éviter les effets secondaires entre les tests, il est conseillé de le faire avant chaque exécution de test:

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

Une autre façon d'activer les annotations Mockito consiste à annoter la classe de test avec @RunWithen spécifiant le MockitoJUnitRunnerqui effectue cette tâche ainsi que d'autres choses utiles:

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

Bibliothèque Spring Boot enveloppant la bibliothèque Mockito

Il s'agit en effet d'une classe Spring Boot :

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

La classe est incluse dans la spring-boot-testbibliothèque.

Il permet d'ajouter des mocks Mockito dans un printemps ApplicationContext.
Si un bean, compatible avec la classe déclarée existe dans le contexte, il le remplace par le mock.
Si ce n'est pas le cas, il ajoute le mock dans le contexte en tant que bean.

Référence Javadoc:

Annotation qui peut être utilisée pour ajouter des simulations à un Spring ApplicationContext.

...

Si un bean unique existant du même type défini dans le contexte sera remplacé par le mock, si aucun bean existant n'est défini, un nouveau sera ajouté.


Quand utiliser Mockito classique / ordinaire et quand utiliser à @MockBeanpartir de Spring Boot?

Les tests unitaires sont conçus pour tester un composant indépendamment des autres composants et les tests unitaires ont également une exigence: être aussi rapide que possible en termes de temps d'exécution car ces tests peuvent être exécutés chaque jour des dizaines de fois sur les machines de développement.

Par conséquent, voici une directive simple:

Lorsque vous écrivez un test qui ne nécessite aucune dépendance du conteneur Spring Boot, le Mockito classique / simple est la voie à suivre: il est rapide et favorise l'isolement du composant testé.
Si votre test doit s'appuyer sur le conteneur Spring Boot et que vous souhaitez également ajouter ou simuler l'un des beans conteneur: à @MockBeanpartir de Spring Boot, c'est le moyen.


Utilisation typique de Spring Boot @MockBean

Au moment où nous écrivons une classe de test annotée avec @WebMvcTest(tranche de test Web).

La documentation de Spring Boot résume très bien cela:

Souvent @WebMvcTestlimité à un seul contrôleur et utilisé en combinaison avec @MockBeanpour fournir des implémentations simulées aux collaborateurs requis.

Voici un exemple :

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'utilisation de @MockBean créera-t-elle une copie du bean et l'injectera-t-elle dans ApplicationContext? Ou le bean simulé aura-t-il toutes ses méthodes comme nulles? Si toutes les méthodes sont nulles, puis-je les stuber comme je peux le faire avec @Mock?
Doug

6
Comme expliqué, l'utilisation @MockBeanremplacera le bean dans le contexte de l'application si un bean déclarant le même type est déjà défini dans votre configuration Spring. Et l'injection est effectuée dans la classe où vous déclarez. @MockBean.Les mécanismes DI fonctionnent de cette manière: vous enregistrez un objet dans le contexte DI puis vous pouvez injecter l'objet référencé dans le contexte Spring dans une classe spécifique. Vous n'injectez pas d'objet dans le contexte DI.
davidxxx

13

À la fin, c'est facile à expliquer. Si vous regardez simplement dans les javadocs des annotations, vous verrez les différents:

@Mock: ( org.mockito.Mock)

Marquez un champ comme une simulation.

  • Permet la création de simulations abrégées.
  • Minimise le code de création de simulation répétitif.
  • Rend la classe de test plus lisible.
  • Rend l'erreur de vérification plus facile à lire car le nom du champ est utilisé pour identifier la maquette.

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

Annotation qui peut être utilisée pour ajouter des simulations à un Spring ApplicationContext. Peut être utilisé comme une annotation de niveau de classe ou sur des champs dans des @Configurationclasses ou des classes de test qui sont @RunWithle SpringRunner.

Les mocks peuvent être enregistrés par type ou par nom de bean. Tout bean unique existant du même type défini dans le contexte sera remplacé par le mock, si aucun bean existant n'est défini, un nouveau sera ajouté.

Quand @MockBeanest utilisé sur un champ, en plus d'être enregistré dans le contexte de l'application, le simulacre sera également injecté dans le champ.

Mockito.mock ()

C'est juste la représentation d'un @Mock.


5
N'oublions pas que @Mock nécessite que le MockitoRunner ou initMocks soit appelé manuellement.
Florian Schaetz

4
Est-ce que la seule différence entre @MockBeanet @Mockcelle-là injectera la simulation dans la Spring ApplicationContextet l'autre ne le fera pas?
Doug

3
@Doug Vous l'avez bien résumé mais il faut se rappeler que MockBean fait partie de Spring Boot
comiventor
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.