Guide rapide sur BDDMockito

Guide rapide sur BDDMockito

1. Vue d'ensemble

Le terme BDD a été inventé en premier parDan North – back in 2006.

BDD encourage la rédaction de tests dans un langage naturel, lisible par l'homme, qui se concentre sur le comportement de l'application.

Il définit une manière clairement structurée de rédiger des tests en trois sections (Arranger, Agir, Assert):

  • given quelques conditions préalables (Organiser)

  • when une action se produit (Act)

  • then vérifie la sortie (Assert)

The Mockito library is shipped with a BDDMockito class which introduces BDD-friendly APIs. Cette API nous permet d'adopter une approche plus conviviale pour BDD en organisant nos tests en utilisantgiven() et en faisant des assertions en utilisantthen().

Dans cet article, nous allons vous expliquer comment configurer nos tests Mockito basés sur BDD. Nous parlerons également des différences entre les APIMockito etBDDMockito, pour éventuellement nous concentrer sur l'APIBDDMockito.

2. Installer

2.1. Dépendances Maven

The BDD flavor of Mockito is part of the mockito-core library, pour commencer, nous devons simplement inclure l'artefact:


    org.mockito
    mockito-core
    2.21.0

Pour la dernière version de Mockito, veuillez vérifierMaven Central.

2.2. Importations

Nos tests peuvent devenir plus lisibles si nous incluons l'importation statique suivante:

import static org.mockito.BDDMockito.*;

Notez queBDDMockito étendMockito, nous ne manquerons donc aucune fonctionnalité fournie par l'API traditionnelleMockito.

3. Mockito vs. BDDMockito

La moquerie traditionnelle dans Mockito est effectuée en utilisantwhen(obj).then*() dans l'étape Arrange.

Plus tard, l'interaction avec notre maquette peut être validée à l'aide deverify() dans l'étape Assert.

BDDMockito fournit des alias BDD pour diverses méthodesMockito, nous pouvons donc écrire notre étape Arrange en utilisantgiven (au lieu dewhen), de même, nous pourrions écrire notre étape Assert en utilisantthen (au lieu deverify).

Examinons un exemple de corps de test utilisant le Mockito traditionnel:

when(phoneBookRepository.contains(momContactName))
  .thenReturn(false);

phoneBookService.register(momContactName, momPhoneNumber);

verify(phoneBookRepository)
  .insert(momContactName, momPhoneNumber);

Voyons comment cela se compare àBDDMockito:

given(phoneBookRepository.contains(momContactName))
  .willReturn(false);

phoneBookService.register(momContactName, momPhoneNumber);

then(phoneBookRepository)
  .should()
  .insert(momContactName, momPhoneNumber);

4. Se moquer avecBDDMockito

Essayons de tester lesPhoneBookService où nous devrons nous moquer desPhoneBookRepository:

public class PhoneBookService {
    private PhoneBookRepository phoneBookRepository;

    public void register(String name, String phone) {
        if(!name.isEmpty() && !phone.isEmpty()
          && !phoneBookRepository.contains(name)) {
            phoneBookRepository.insert(name, phone);
        }
    }

    public String search(String name) {
        if(!name.isEmpty() && phoneBookRepository.contains(name)) {
            return phoneBookRepository.getPhoneNumberByContactName(name);
        }
        return null;
    }
}

BDDMockito commeMockito nous permet de renvoyer une valeur qui peut être fixe ou dynamique. Cela nous permettrait également de lever une exception:

4.1. Renvoyer une valeur fixe

En utilisantBDDMockito,, nous pourrions facilement configurer Mockito pour renvoyer un résultat fixe chaque fois que notre méthode cible d'objet fictif est appelée:

given(phoneBookRepository.contains(momContactName))
  .willReturn(false);

phoneBookService.register(xContactName, "");

then(phoneBookRepository)
  .should(never())
  .insert(momContactName, momPhoneNumber);

4.2. Renvoyer une valeur dynamique

BDDMockito nous permet de fournir une manière plus sophistiquée de renvoyer des valeurs. Nous pourrions retourner un résultat dynamique basé sur l'entrée:

given(phoneBookRepository.contains(momContactName))
  .willReturn(true);
given(phoneBookRepository.getPhoneNumberByContactName(momContactName))
  .will((InvocationOnMock invocation) ->
    invocation.getArgument(0).equals(momContactName)
      ? momPhoneNumber
      : null);
phoneBookService.search(momContactName);
then(phoneBookRepository)
  .should()
  .getPhoneNumberByContactName(momContactName);

4.3. Lancer une exception

Dire à Mockito de lancer une exception est assez simple:

given(phoneBookRepository.contains(xContactName))
  .willReturn(false);
willThrow(new RuntimeException())
  .given(phoneBookRepository)
  .insert(any(String.class), eq(tooLongPhoneNumber));

try {
    phoneBookService.register(xContactName, tooLongPhoneNumber);
    fail("Should throw exception");
} catch (RuntimeException ex) { }

then(phoneBookRepository)
  .should(never())
  .insert(momContactName, tooLongPhoneNumber);

Remarquez comment nous avons échangé les positions degiven etwill*, c'est obligatoire au cas où nous nous moquions d'une méthode qui n'a pas de valeur de retour.

Notez également que nous avons utilisé des corrélateurs d'arguments comme (any,eq) pour fournir une manière plus générique de se moquer basée sur des critères plutôt que sur une valeur fixe.

5. Conclusion

Dans ce rapide tutoriel, nous avons discuté de la manière dont BDDMockito essaie d'apporter une ressemblance BDD à nos tests Mockito, et nous avons discuté de certaines des différences entreMockito etBDDMockito.

Comme toujours, le code source peut être trouvéover on GitHub - dans le package de testcom.example.bddmockito.