Mockito ArgumentMatchers

1. Panoramica

Questo tutorial mostra come usare ArgumentMatcher e come differisce da ArgumentCaptor .

Per un'introduzione al framework Mockito, fare riferimento a questo articolo.

2. Dipendenze di Maven

Dobbiamo aggiungere un singolo artefatto:

 org.mockito mockito-core 2.21.0 test 

L'ultima versione di Mockito può essere trovata su Maven Central .

3. ArgumentMatchers

È possibile configurare un metodo deriso in vari modi. Uno di questi è restituire valori fissi:

doReturn("Flower").when(flowerService).analyze("poppy");

Nell'esempio precedente, la stringa "Flower" viene restituita solo quando il servizio di analisi riceve la stringa "poppy".

Ma forse dobbiamo rispondere a una gamma più ampia di valori o a valori precedentemente sconosciuti .

In tutti questi scenari, possiamo configurare i nostri metodi derisi con abbinatori di argomenti :

when(flowerService.analyze(anyString())).thenReturn("Flower");

Ora, a causa del matcher dell'argomento anyString , il risultato sarà lo stesso indipendentemente dal valore che passiamo per analizzare. ArgumentMatchers ci consente una verifica flessibile o stubbing.

Nel caso in cui un metodo abbia più di un argomento, non è possibile utilizzare ArgumentMatchers solo per alcuni degli argomenti . Mockito richiede di fornire tutti gli argomenti tramite abbinatori o valori esatti.

Un prossimo esempio è un approccio errato a questo:

abstract class FlowerService { public abstract boolean isABigFlower(String name, int petals); } FlowerService mock = mock(FlowerService.class); when(mock.isABigFlower("poppy", anyInt())).thenReturn(true);

Per risolverlo e mantenere il nome della stringa "poppy" come desiderato, useremo eq matcher :

when(mock.isABigFlower(eq("poppy"), anyInt())).thenReturn(true);

Ci sono altri due punti a cui prestare attenzione quando vengono utilizzati i matcher :

  • Non possiamo usarli come valore di ritorno , è richiesto un valore esatto quando si stub le chiamate
  • Infine, non possiamo usare abbinatori di argomenti al di fuori della verifica o dello stubbing

Nell'ultimo caso, Mockito rileverà l'argomento fuori posto e genererà un'eccezione InvalidUseOfMatchersException .

Un cattivo esempio potrebbe essere:

String orMatcher = or(eq("poppy"), endsWith("y")); verify(mock).analyze(orMatcher);

Il modo per implementare il codice sopra è:

verify(mock).analyze(or(eq("poppy"), endsWith("y")));

Mockito fornisce anche AdditionalMatcher per implementare operazioni logiche comuni ('not', 'and', 'or') su ArgumentMatcher che corrispondono a tipi primitivi e non primitivi:

verify(mock).analyze(or(eq("poppy"), endsWith("y")));

4. Corrispondenza argomenti personalizzata

Creare il nostro matcher può essere utile per selezionare il miglior approccio possibile per un dato scenario e produrre test di altissima qualità , puliti e manutenibili.

Ad esempio, potremmo avere un MessageController che consegna i messaggi. Riceverà un MessageDTO e da questo creerà un messaggio che verrà consegnato da MessageService .

La nostra verifica sarà semplice, verifica di aver chiamato il MessageService esattamente 1 volta con qualsiasi messaggio:

verify(messageService, times(1)).deliverMessage(any(Message.class));

Poiché il messaggio è costruito all'interno del metodo in prova , siamo costretti a usare any come matcher .

Questo approccio non ci consente di convalidare i dati all'interno del Message , che possono essere diversi rispetto ai dati all'interno di MessageDTO .

Per questo motivo, implementeremo un abbinamento di argomenti personalizzati:

public class MessageMatcher implements ArgumentMatcher { private Message left; // constructors @Override public boolean matches(Message right) { return left.getFrom().equals(right.getFrom()) && left.getTo().equals(right.getTo()) && left.getText().equals(right.getText()) && right.getDate() != null && right.getId() != null; } }

Per utilizzare il nostro matcher, dobbiamo modificare il nostro test e sostituire any con argThat :

verify(messageService, times(1)).deliverMessage(argThat(new MessageMatcher(message)));

Now we know our Message instance will have the same data as our MessageDTO.

5. Custom Argument Matcher vs. ArgumentCaptor

Both techniques custom argument matchers and ArgumentCaptor can be used for making sure certain arguments were passed to mocks.

However,ArgumentCaptor may be a better fit if we need it to assert on argument values to complete verification or our custom argument matcher is not likely to be reused.

Custom argument matchers via ArgumentMatcher are usually better for stubbing.

6. Conclusion

In questo articolo, abbiamo esplorato una funzionalità di Mockito , ArgumentMatcher e la sua differenza con ArgumentCaptor .

Come sempre, il codice sorgente completo degli esempi è disponibile su GitHub.