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"));
}
}