Premiers pas avec Mockito @Mock, @Spy, @Captor et @InjectMocks

Premiers pas avec Mockito @Mock, @Spy, @Captor et @InjectMocks

1. Vue d'ensemble

Dans ce tutoriel, nous aborderons lesannotations of the Mockito library -@Mock,@Spy,@Captor et@InjectMocks.

Pour plus de bonté Mockito,have a look at the series here.

Lectures complémentaires:

Mockito - Utiliser des espions

Faire bon usage des Spies dans Mockito et leur différence entre les espions et les fous.

Read more

Mockito vs EasyMock vs JMockit

Un guide rapide et pratique pour comprendre et comparer les bibliothèques moqueuses Java.

Read more

Injecter Mockito se moque des haricots de printemps

Cet article expliquera comment utiliser l’injection de dépendance pour insérer des prototypes Mockito dans Spring Beans à des fins de test unitaire.

Read more

2. Activer les annotations Mockito

Tout d'abord, voyons comment activer l'utilisation d'annotations avec les tests Mockito.

Pour que ces annotations soient activées, nous devonsannotate the JUnit test with a runner -MockitoJUnitRunner comme dans l'exemple suivant:

@RunWith(MockitoJUnitRunner.class)
public class MockitoAnnotationTest {
    ...
}

Alternativement, nous pouvons aussienable these annotations programmatically, en invoquantMockitoAnnotations.initMocks() comme dans l'exemple suivant:

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

3. Annotation@Mock

L'annotation la plus utilisée dans Mockito est@Mock. Nous pouvons utiliser@Mock pour créer et injecter des instances simulées sans avoir à appelerMockito.mock manuellement.

Dans l'exemple suivant, nous allons créer unArrayList simulé avec la méthode manuelle sans utiliser l'annotation@Mock:

@Test
public void whenNotUseMockAnnotation_thenCorrect() {
    List mockList = Mockito.mock(ArrayList.class);

    mockList.add("one");
    Mockito.verify(mockList).add("one");
    assertEquals(0, mockList.size());

    Mockito.when(mockList.size()).thenReturn(100);
    assertEquals(100, mockList.size());
}

Et maintenant, nous allons faire la même chose mais nous allons injecter le simulacre en utilisant l'annotation@Mock:

@Mock
List mockedList;

@Test
public void whenUseMockAnnotation_thenMockIsInjected() {
    mockedList.add("one");
    Mockito.verify(mockedList).add("one");
    assertEquals(0, mockedList.size());

    Mockito.when(mockedList.size()).thenReturn(100);
    assertEquals(100, mockedList.size());
}

Notez comment - dans les deux exemples, nous interagissons avec la maquette et vérifions certaines de ces interactions - juste pour nous assurer que la maquette se comporte correctement.

4. Annotation@Spy

Voyons maintenant comment utiliser l'annotation@Spy pour espionner une instance existante.

Dans l'exemple suivant - nous créons un espion d'unList avec l'ancienne méthode sans utiliser l'annotation@Spy:

@Test
public void whenNotUseSpyAnnotation_thenCorrect() {
    List spyList = Mockito.spy(new ArrayList());

    spyList.add("one");
    spyList.add("two");

    Mockito.verify(spyList).add("one");
    Mockito.verify(spyList).add("two");

    assertEquals(2, spyList.size());

    Mockito.doReturn(100).when(spyList).size();
    assertEquals(100, spyList.size());
}

Faisons maintenant de même - espionnez la liste - mais faites-le en utilisant l'annotation@Spy:

@Spy
List spiedList = new ArrayList();

@Test
public void whenUseSpyAnnotation_thenSpyIsInjectedCorrectly() {
    spiedList.add("one");
    spiedList.add("two");

    Mockito.verify(spiedList).add("one");
    Mockito.verify(spiedList).add("two");

    assertEquals(2, spiedList.size());

    Mockito.doReturn(100).when(spiedList).size();
    assertEquals(100, spiedList.size());
}

Remarquez comment, comme auparavant, nous interagissons avec l’espion ici pour nous assurer qu’il se comporte correctement. Dans cet exemple nous:

  • Utilisation de la méthoderealspiedList.add() pour ajouter des éléments auxspiedList.

  • Stubbed la méthodespiedList.size() pour renvoyer100 au lieu de2 en utilisantMockito.doReturn().

5. Annotation@Captor

Ensuite, voyons comment utiliser l'annotation@Captor pour créer une instanceArgumentCaptor.

Dans l'exemple suivant - nous créons unArgumentCaptor avec l'ancienne méthode sans utiliser l'annotation@Captor:

@Test
public void whenNotUseCaptorAnnotation_thenCorrect() {
    List mockList = Mockito.mock(List.class);
    ArgumentCaptor arg = ArgumentCaptor.forClass(String.class);

    mockList.add("one");
    Mockito.verify(mockList).add(arg.capture());

    assertEquals("one", arg.getValue());
}

Faisons maintenantmake use of @Captor dans le même but - pour créer une instanceArgumentCaptor:

@Mock
List mockedList;

@Captor
ArgumentCaptor argCaptor;

@Test
public void whenUseCaptorAnnotation_thenTheSam() {
    mockedList.add("one");
    Mockito.verify(mockedList).add(argCaptor.capture());

    assertEquals("one", argCaptor.getValue());
}

Notez que le test devient plus simple et plus lisible lorsque nous éliminons la logique de configuration.

6. Annotation@InjectMocks

Voyons maintenant comment utiliser l'annotation@InjectMocks pour injecter automatiquement des champs simulés dans l'objet testé.

Dans l'exemple suivant - nous utilisons@InjectMocks pour injecter le mockwordMap dans leMyDictionarydic:

@Mock
Map wordMap;

@InjectMocks
MyDictionary dic = new MyDictionary();

@Test
public void whenUseInjectMocksAnnotation_thenCorrect() {
    Mockito.when(wordMap.get("aWord")).thenReturn("aMeaning");

    assertEquals("aMeaning", dic.getMeaning("aWord"));
}

Et voici la classeMyDictionary:

public class MyDictionary {
    Map wordMap;

    public MyDictionary() {
        wordMap = new HashMap();
    }
    public void add(final String word, final String meaning) {
        wordMap.put(word, meaning);
    }
    public String getMeaning(final String word) {
        return wordMap.get(word);
    }
}

7. Injecter une maquette dans un espion

Semblable au test ci-dessus, nous pourrions vouloir injecter une maquette à un espion:

@Mock
Map wordMap;

@Spy
MyDictionary spyDic = new MyDictionary();

However, Mockito doesn’t support injecting mocks into spies, et le test suivant aboutit à une exception:

@Test
public void whenUseInjectMocksAnnotation_thenCorrect() {
    Mockito.when(wordMap.get("aWord")).thenReturn("aMeaning");

    assertEquals("aMeaning", spyDic.getMeaning("aWord"));
}

Si nous voulons utiliser une maquette avec un espion, nous pouvons injecter manuellement la maquette via un constructeur:

MyDictionary(Map wordMap) {
    this.wordMap = wordMap;
}

Au lieu d'utiliser l'annotation, nous pouvons maintenant créer l'espion manuellement:

@Mock
Map wordMap;

MyDictionary spyDic;

@Before
public void init() {
    MockitoAnnotations.initMocks(this);
    spyDic = Mockito.spy(new MyDictionary(wordMap));
}

Le test va maintenant passer.

8. Exécution dans NPE lors de l'utilisation de l'annotation __

Souvent, nous pouvonsrun into NullPointerException w lorsque nous essayons d'utiliser réellement l'instance annotée avec@Mockor@Spy, comme dans l'exemple:

public class NPETest {

    @Mock
    List mockedList;

    @Test
    public void test() {
        Mockito.when(mockedList.size()).thenReturn(1);
    }
}

La plupart du temps, cela se produit simplement parce que nous avons oublié d'activer correctement les annotations Mockito.

Nous devons donc garder à l'esprit que chaque fois que nous voulons utiliser les annotations Mockito, nous devons franchir une étape supplémentaire et les initialiser comme nous l'avons déjà expliqué.

9. Remarques

Enfin - voicisome notes sur les annotations Mockito:

  • Utiliser une annotation pour minimiser le code de création répétée

  • Utiliser une annotation pour rendre le test plus lisible

  • Utilisez@InjectMocks pour injecter les instances@Spy et@Mock

10. Conclusion

Dans ce rapide tutoriel, nous avons montré les bases deannotations in the Mockito library.

L'implémentation de tous ces exemples peut être trouvéeover on GitHub. Ceci est un projet Maven, il devrait donc être facile à importer et à exécuter tel quel.

Et bien sûr, pour plus de bonté Mockito,have a look at the series here.