Guida rapida a BDDMockito

1. Panoramica

Il termine BDD è stato coniato per la prima volta da Dan North nel 2006.

BDD incoraggia la scrittura di test in un linguaggio naturale e leggibile dall'uomo che si concentra sul comportamento dell'applicazione.

Definisce un modo chiaramente strutturato di scrivere i test seguendo tre sezioni (Arrange, Act, Assert):

  • date alcune precondizioni (Arrange)
  • quando si verifica un'azione (Act)
  • quindi verifica l'output (Assert)

La libreria Mockito viene fornita con una classe BDDMockito che introduce API compatibili con BDD. Questa API ci consente di adottare un approccio più amichevole BDD organizzando i nostri test usando given () e facendo asserzioni usando then () .

In questo articolo, spiegheremo come configurare i nostri test Mockito basati su BDD. Parleremo anche delle differenze tra le API Mockito e BDDMockito , per concentrarci infine sull'API BDDMockito .

2. Configurazione

2.1. Dipendenze di Maven

Il gusto BDD di Mockito fa parte della libreria mockito-core , per iniziare dobbiamo solo includere l'artefatto:

 org.mockito mockito-core 2.21.0 

Per l'ultima versione di Mockito, controllare Maven Central.

2.2. Importazioni

I nostri test possono diventare più leggibili se includiamo la seguente importazione statica:

import static org.mockito.BDDMockito.*;

Si noti che BDDMockito estende Mockito , quindi non perderemo nessuna funzionalità fornita dalla tradizionale API Mockito .

3. Mockito contro BDDMockito

Il tradizionale beffardo in Mockito viene eseguito usando quando (obj) . quindi * () nel passaggio Arrange.

Successivamente, l'interazione con il nostro mock può essere convalidata utilizzando verify () nel passaggio Assert.

BDDMockito fornisce alias BDD per vari metodi Mockito , quindi possiamo scrivere il nostro passaggio Arrange usando dato (invece di quando ), allo stesso modo, potremmo scrivere il nostro passaggio Assert usando then (invece di verificare ).

Diamo un'occhiata a un esempio di un corpo di prova che utilizza il Mockito tradizionale:

when(phoneBookRepository.contains(momContactName)) .thenReturn(false); phoneBookService.register(momContactName, momPhoneNumber); verify(phoneBookRepository) .insert(momContactName, momPhoneNumber);

Vediamo come si confronta con BDDMockito :

given(phoneBookRepository.contains(momContactName)) .willReturn(false); phoneBookService.register(momContactName, momPhoneNumber); then(phoneBookRepository) .should() .insert(momContactName, momPhoneNumber);

4. Schernire con BDDMockito

Proviamo a testare PhoneBookService in cui dovremo simulare il PhoneBookRepository:

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 come Mockito ci consente di restituire un valore che può essere fisso o dinamico. Ci consentirebbe anche di lanciare un'eccezione:

4.1. Restituzione di un valore fisso

Utilizzando BDDMockito, potremmo facilmente configurare Mockito per restituire un risultato fisso ogni volta che viene richiamato il nostro metodo di destinazione dell'oggetto fittizio:

given(phoneBookRepository.contains(momContactName)) .willReturn(false); phoneBookService.register(xContactName, ""); then(phoneBookRepository) .should(never()) .insert(momContactName, momPhoneNumber);

4.2. Restituzione di un valore dinamico

BDDMockito ci consente di fornire un modo più sofisticato per restituire valori. Potremmo restituire un risultato dinamico basato sull'input:

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. Lanciare un'eccezione

Dire a Mockito di lanciare un'eccezione è piuttosto semplice:

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

Nota come abbiamo scambiato le posizioni di data e volontà * , obbligatorio nel caso in cui stiamo prendendo in giro un metodo che non ha valore di ritorno.

Si noti inoltre che abbiamo utilizzato abbinamenti di argomenti come ( any , eq ) per fornire un modo più generico di deridere basato su criteri piuttosto che dipendere da un valore fisso.

5. conclusione

In questo breve tutorial, abbiamo discusso di come BDDMockito cerca di portare una somiglianza BDD ai nostri test Mockito e abbiamo discusso alcune delle differenze tra Mockito e BDDMockito .

Come sempre, il codice sorgente può essere trovato su GitHub - all'interno del pacchetto di test com.baeldung.bddmockito .