227 votes

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

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

  1. @MockBean :

    @MockBean
    MyService myservice;
  2. @Mock :

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

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

291voto

davidh Points 107

Bibliothèque Mockito simple

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

y

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

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

La voie utilisant l'annotation est plus courte, donc préférable et souvent préférée.


Notez que pour activer les annotations Mockito pendant les exécutions de test, l'option MockitoAnnotations.initMocks(this) La 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 de Mockito est d'annoter la classe de test avec @RunWith en spécifiant le MockitoJUnitRunner qui fait cette tâche et aussi 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'un Classe Spring Boot :

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

La classe est incluse dans le spring-boot-test bibliothèque.

Il permet d'ajouter des mocks Mockito dans un Spring ApplicationContext .
Si un haricot, compatible avec la classe déclarée, existe dans le contexte, il remplace par la moquerie.
Si ce n'est pas le cas, il ajoute l'objet fictif dans le contexte comme un bean.

Référence Javadoc :

Annotation qui peut être utilisée pour ajouter des objets fantaisie à un modèle de Spring. ApplicationContext.

...

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


Quand utiliser Mockito classique/plain et quand utiliser @MockBean de Spring Boot ?

Les tests unitaires sont conçus pour tester un composant de manière isolée 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 des développeurs.

Par conséquent, voici une ligne directrice simple :

Si vous écrivez un test qui ne nécessite aucune dépendance du conteneur Spring Boot, le Mockito classique/plain est la voie à suivre : il est rapide et favorise l'isolation du composant testé.
Si votre test doit s'appuyer sur le conteneur Spring Boot y vous souhaitez également ajouter ou modifier l'un des haricots du conteneur : @MockBean à partir de Spring Boot est la solution.


Utilisation typique de Spring Boot @MockBean

Lorsque nous écrivons une classe de test annotée de @WebMvcTest (tranche de test web).

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

Souvent @WebMvcTest seront limités à un seul contrôleur et utilisés en combinaison avec @MockBean pour fournir des implémentations fictives pour collaborateurs nécessaires.

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 votes

L'utilisation de @MockBean va-t-elle créer une copie du bean et l'injecter dans l'ApplicationContext ? Ou est-ce que le bean simulé aura toutes ses méthodes comme nulles ? Si toutes les méthodes sont nulles, puis-je les stuber comme je peux le faire avec @Mock ?

6 votes

Comme expliqué, l'utilisation de @MockBean remplacera 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 la manière suivante : vous enregistrez un objet dans le contexte DI et ensuite vous pouvez injecter l'objet référencé dans le contexte Spring dans une classe spécifique. On n'injecte pas un objet dans le contexte DI.

25voto

Patrick Points 691

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

@Mock : ( org.mockito.Mock )

Marquer un champ comme étant un simulacre.

  • Permet de créer une maquette en raccourci.
  • Réduit au minimum le code répétitif de création de simulacre.
  • Rend la classe de test plus lisible.
  • Rend l'erreur de vérification plus facile à lire parce que le nom du champ est utilisé pour identifier le simulacre.

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

Annotation qui peut être utilisée pour ajouter des mocks à un Spring ApplicationContext. Peut être utilisée comme une annotation au niveau de la classe ou sur les champs dans l'une des deux catégories suivantes @Configuration ou des classes de test qui sont @RunWith le 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 @MockBean est utilisé sur un champ, en plus d'être enregistré dans le contexte de l'application, l'objet fantaisie sera également injecté dans le champ.

Mockito.mock()

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

6 votes

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

9 votes

Est-ce que la seule différence entre @MockBean y @Mock que l'on injectera le simulacre dans le Spring ApplicationContext et l'autre pas ?

4 votes

@Doug Vous l'avez bien résumé, mais il faut se rappeler que MockBean fait partie de Spring Boot.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X