Differenza tra i metodi when () e doXxx () in Mockito

1. Introduzione

Mockito è un popolare framework Java mocking. Con esso, è semplice creare oggetti fittizi, configurare comportamenti fittizi, acquisire argomenti del metodo e verificare le interazioni con i mock.

Ora ci concentreremo sulla specifica del comportamento fittizio. Abbiamo due modi per farlo: la sintassi when (). ThenDoSomething () e doSomething (). When () .

In questo breve tutorial, vedremo perché li abbiamo entrambi.

2. metodo when ()

Consideriamo la seguente interfaccia Employee :

interface Employee { String greet(); void work(DayOfWeek day); }

Nei nostri test, usiamo una simulazione di questa interfaccia. Supponiamo di voler configurare il metodo greet () del mock per restituire la stringa "Hello" . È semplice farlo utilizzando il metodo when () di Mockito :

@Test void givenNonVoidMethod_callingWhen_shouldConfigureBehavior() { // given when(employee.greet()).thenReturn("Hello"); // when String greeting = employee.greet(); // then assertThat(greeting, is("Hello")); }

Che succede? L' oggetto dipendente è una finta. Quando chiamiamo uno dei suoi metodi, Mockito registra quella chiamata. Con la chiamata del metodo when () , Mockito sa che questa invocazione non era un'interazione da parte della logica aziendale. Era un'affermazione che vogliamo assegnare un comportamento all'oggetto fittizio. Dopodiché, con uno dei metodi thenXxx () , specifichiamo il comportamento previsto.

Fino a questo punto, è una buona vecchia presa in giro. Allo stesso modo, vogliamo configurare il metodo work () per lanciare un'eccezione, quando lo chiamiamo con un argomento di domenica:

@Test void givenVoidMethod_callingWhen_wontCompile() { // given when(employee.work(DayOfWeek.SUNDAY)).thenThrow(new IAmOnHolidayException()); // when Executable workCall = () -> employee.work(DayOfWeek.SUNDAY); // then assertThrows(IAmOnHolidayException.class, workCall); }

Sfortunatamente, questo codice non verrà compilato, perché nella chiamata work (dipendente.work (…)) , il metodo work () ha un tipo di ritorno void ; quindi non possiamo avvolgerlo in un'altra chiamata di metodo. Significa che non possiamo deridere i metodi del vuoto? Certo che possiamo. metodi doXxx in soccorso!

3. metodi doXxx ()

Vediamo come possiamo configurare la generazione di eccezioni con il metodo doThrow () :

@Test void givenVoidMethod_callingDoThrow_shouldConfigureBehavior() { // given doThrow(new IAmOnHolidayException()).when(employee).work(DayOfWeek.SUNDAY); // when Executable workCall = () -> employee.work(DayOfWeek.SUNDAY); // then assertThrows(IAmOnHolidayException.class, workCall); }

Questa sintassi è leggermente diversa dalla precedente: non cerchiamo di avvolgere una chiamata di metodo void all'interno di un'altra chiamata di metodo. Pertanto, questo codice viene compilato.

Vediamo cosa è appena successo. Innanzitutto, abbiamo affermato di voler lanciare un'eccezione. Successivamente, abbiamo chiamato il metodo when () e abbiamo passato l'oggetto mock. Successivamente, abbiamo specificato quale comportamento dell'interazione fittizia vogliamo configurare.

Nota che questo non è lo stesso metodo when () che abbiamo usato prima. Inoltre, nota che abbiamo concatenato l'interazione fittizia dopo l'invocazione di when (). Nel frattempo, l'abbiamo definito tra parentesi con la prima sintassi.

Perché abbiamo il primo quando (). ThenXxx () , quando non è in grado di svolgere un'attività così comune, come configurare un'invocazione void ? Presenta molteplici vantaggi rispetto alla sintassi doXxx (). When () .

In primo luogo, è più logico che gli sviluppatori scrivano e leggano affermazioni come "quando interazione, poi fai qualcosa" che "fai qualcosa, quando interazione".

In secondo luogo, possiamo aggiungere più comportamenti alla stessa interazione con il concatenamento. Questo perché when () restituisce un'istanza della classe OngoingStubbing , i cui metodi thenXxx () restituiscono lo stesso tipo.

D'altra parte, i metodi doXxx () restituiscono un'istanza di Stubber e Stubber.when (T mock) restituisce T , quindi possiamo specificare che tipo di invocazione del metodo vogliamo configurare. Ma T fa parte della nostra applicazione, ad esempio, Employee nei nostri frammenti di codice. Ma T non restituirà una classe Mockito, quindi non saremo in grado di aggiungere più comportamenti con il concatenamento.

4. BDDMockito

BDDMockito utilizza una sintassi alternativa a quelle che abbiamo trattato. È piuttosto semplice: nelle nostre configurazioni fittizie, dobbiamo sostituire la parola chiave " quando" con " dato " e la parola chiave " fare " con " volontà ". A parte questo, il nostro codice rimane lo stesso:

@Test void givenNonVoidMethod_callingGiven_shouldConfigureBehavior() { // given given(employee.greet()).willReturn("Hello"); // when String greeting = employee.greet(); // then assertThat(greeting, is("Hello")); } @Test void givenVoidMethod_callingWillThrow_shouldConfigureBehavior() { // given willThrow(new IAmOnHolidayException()).given(employee).work(DayOfWeek.SUNDAY); // when Executable workCall = () -> employee.work(DayOfWeek.SUNDAY); // then assertThrows(IAmOnHolidayException.class, workCall); }

5. conclusione

Abbiamo visto i vantaggi e gli svantaggi della configurazione di un oggetto fittizio in modalità when (). ThenXxx () o doXxx (). When () . Inoltre, abbiamo visto come funzionano queste sintassi e perché le abbiamo entrambe.

Come al solito, gli esempi sono disponibili su GitHub.