Testare i callback con Mockito

1. Panoramica

In questo breve tutorial, ci concentreremo su come testare i callback utilizzando il popolare framework di test Mockito.

Esploreremo due soluzioni, in primo luogo utilizzando un ArgumentCaptor e poi l'intuitivo metodo doAnswer () .

Per saperne di più su come testare bene con Mockito, dai un'occhiata alla nostra serie Mockito qui.

2. Introduzione ai callback

Un callback è un pezzo di codice che viene passato come argomento a un metodo, che dovrebbe richiamare (eseguire) l'argomento in un dato momento .

Questa esecuzione può essere immediata come in un callback sincrono, ma più tipicamente potrebbe avvenire in un secondo momento come in un callback asincrono.

Uno scenario comune per l'utilizzo dei callback è durante le interazioni del servizio quando è necessario elaborare la risposta da una chiamata di servizio .

In questo tutorial, utilizzeremo l' interfaccia del servizio mostrata di seguito come collaboratore nei casi di test:

public interface Service { void doAction(String request, Callback callback); }

Nella richiamata argomento passiamo una classe che gestirà la risposta utilizzando il risposta (risposta T) Metodo:

public interface Callback { void reply(T response); } 

2.1. Un servizio semplice

Useremo anche un semplice esempio di servizio per dimostrare come passare e invocare la richiamata :

public void doAction() { service.doAction("our-request", new Callback() { @Override public void reply(Response response) { handleResponse(response); } }); } 

Il metodo handleResponse verifica se la risposta è valida prima di aggiungere alcuni dati all'oggetto Response :

private void handleResponse(Response response) { if (response.isValid()) { response.setData(new Data("Successful data response")); } }

Per chiarezza, abbiamo scelto di non utilizzare un'espressione Java Lamda, ma la chiamata service.doAction potrebbe anche essere scritta in modo più conciso :

service.doAction("our-request", response -> handleResponse(response)); 

Per saperne di più sulle espressioni Lambda, dai un'occhiata qui.

3. Utilizzo di un ArgumentCaptor

Ora diamo un'occhiata a come usiamo Mockito per afferrare l' oggetto Callback usando un ArgumentCaptor :

@Test public void givenServiceWithValidResponse_whenCallbackReceived_thenProcessed() { ActionHandler handler = new ActionHandler(service); handler.doAction(); verify(service).doAction(anyString(), callbackCaptor.capture()); Callback callback = callbackCaptor.getValue(); Response response = new Response(); callback.reply(response); String expectedMessage = "Successful data response"; Data data = response.getData(); assertEquals( "Should receive a successful message: ", expectedMessage, data.getMessage()); }

In questo esempio, creiamo prima un ActionHandler prima di chiamare il metodo doAction di questo gestore. Questo è semplicemente un wrapper per la nostra chiamata al metodo doAction del servizio semplice , che è dove invochiamo il nostro callback.

Successivamente, verifichiamo che doAction è stato chiamato sulla nostra istanza del servizio fittizio passando anyString () come primo argomento e callbackCaptor.capture () come secondo, che è dove catturiamo l' oggetto Callback . Il metodo getValue () può quindi essere utilizzato per restituire il valore catturato dell'argomento.

Ora che abbiamo l' oggetto Callback , creiamo un oggetto Response che è valido per impostazione predefinita prima di chiamare direttamente il metodo di risposta e affermare che i dati di risposta hanno il valore corretto .

4. Utilizzo del metodo doAnswer ()

Ora esamineremo una soluzione comune per i metodi di stubbing che hanno callback utilizzando l' oggetto Answer di Mockito e il metodo doAnswer per bloccare il metodo void doAction:

@Test public void givenServiceWithInvalidResponse_whenCallbackReceived_thenNotProcessed() { Response response = new Response(); response.setIsValid(false); doAnswer((Answer) invocation -> { Callback callback = invocation.getArgument(1); callback.reply(response); Data data = response.getData(); assertNull("No data in invalid response: ", data); return null; }).when(service) .doAction(anyString(), any(Callback.class)); ActionHandler handler = new ActionHandler(service); handler.doAction(); } 

E, nel nostro secondo esempio, creiamo prima un oggetto Response non valido che verrà utilizzato in seguito nel test.

Successivamente, impostiamo la risposta sul nostro servizio fittizio in modo che quando viene chiamato doAction , intercettiamo l'invocazione e prendiamo gli argomenti del metodo utilizzando invocation.getArgument (1) per ottenere l' argomento Callback .

L'ultimo passaggio consiste nel creare ActionHandler e chiamare doAction che fa invocare la risposta .

Per saperne di più sui metodi di stubbing void, dai un'occhiata qui.

3. Conclusione

In questo breve articolo, abbiamo coperto due diversi modi per affrontare i callback di test durante i test con Mockito.

Come sempre, gli esempi sono disponibili in questo progetto GitHub.