Introduzione a JUnitParams

1. Panoramica

In questo articolo, esploreremo la libreria JUnitParams e i suoi utilizzi. In poche parole, questa libreria fornisce una facile parametrizzazione dei metodi di test nei test JUnit .

Ci sono situazioni in cui l'unica cosa che cambia tra più test sono i parametri. JUnit stesso ha un supporto per la parametrizzazione e JUnitParams migliora significativamente questa funzionalità.

2. Dipendenza da Maven

Per utilizzare JUnitParams nel nostro progetto, dobbiamo aggiungerlo al nostro pom.xml :

 pl.pragmatists JUnitParams 1.1.0 

L'ultima versione della libreria può essere trovata qui.

3. Scenario di prova

Creiamo una classe che fa l'addizione sicura di due numeri interi. Questo dovrebbe restituire Integer.MAX_VALUE se va in overflow e Integer.MIN_VALUE se va in underflow:

public class SafeAdditionUtil { public int safeAdd(int a, int b) { long result = ((long) a) + b; if (result > Integer.MAX_VALUE) { return Integer.MAX_VALUE; } else if (result < Integer.MIN_VALUE) { return Integer.MIN_VALUE; } return (int) result; } }

4. Costruire un metodo di prova semplice

Avremo bisogno di testare l'implementazione del metodo per diverse combinazioni di valori di input, per assicurarci che l'implementazione sia vera per tutti i possibili scenari. JUnitParams fornisce più di un modo per ottenere la creazione di test parametrizzati.

Prendiamo l'approccio di base con una quantità minima di codice e vediamo come è fatto. Successivamente, possiamo vedere quali sono gli altri possibili modi di implementare gli scenari di test utilizzando JUnitParams :

@RunWith(JUnitParamsRunner.class) public class SafeAdditionUtilTest { private SafeAdditionUtil serviceUnderTest = new SafeAdditionUtil(); @Test @Parameters({ "1, 2, 3", "-10, 30, 20", "15, -5, 10", "-5, -10, -15" }) public void whenWithAnnotationProvidedParams_thenSafeAdd( int a, int b, int expectedValue) { assertEquals(expectedValue, serviceUnderTest.safeAdd(a, b)); } }

Ora vediamo come questa classe di test differisce da una normale classe di test JUnit .

La prima cosa che notiamo è che c'è un test runner diverso nell'annotazione della classe: JUnitParamsRunner .

Passando al metodo di test, vediamo che il metodo di test è annotato con l' annotazione @Parameters con un array di parametri di input. Indica diversi scenari di test che verranno utilizzati per testare il nostro metodo di servizio.

Se eseguiamo il test utilizzando Maven, vedremo che stiamo eseguendo quattro casi di test e non uno solo . L'output sarebbe simile al seguente:

------------------------------------------------------- T E S T S ------------------------------------------------------- Running com.baeldung.junitparams.SafeAdditionUtilTest Tests run: 4, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.068 sec - in com.baeldung.junitparams.SafeAdditionUtilTest Results : Tests run: 4, Failures: 0, Errors: 0, Skipped: 0

5. Diversi tipi di parametrizzazione dei metodi di prova

Fornire i parametri del test direttamente nell'annotazione non è certamente il modo più leggibile se abbiamo molti possibili scenari che devono essere testati. JUnitParams offre una serie di diversi approcci che possiamo utilizzare per creare i test parametrizzati:

  • Direttamente nell'annotazione @Parameters (usata nell'esempio sopra)
  • Utilizzo di un metodo di test denominato definito all'interno dell'annotazione
  • Utilizzo di un metodo mappato in base al nome del metodo di prova
  • Una classe di test denominata definita all'interno dell'annotazione
  • Utilizzando un file CSV

Esploriamo gli approcci uno per uno.

5.1. Direttamente nel parametro @ annotazione

Abbiamo già utilizzato questo approccio nell'esempio che abbiamo provato. Quello che dobbiamo tenere a mente è che dovremmo fornire un array di stringhe di parametri. All'interno della stringa del parametro, ogni parametro è separato da una virgola.

Ad esempio, la matrice sarebbe nella forma di {"1, 2, 3", "-10, 30, 20"} e un set di parametri è rappresentato come "1, 2, 3" .

Il limite di questo approccio è che possiamo fornire solo primitive e String come parametri di test. Non è possibile inviare oggetti anche come parametri del metodo di prova.

5.2. Metodo dei parametri

Possiamo fornire i parametri del metodo di test utilizzando un altro metodo all'interno della classe. Vediamo prima un esempio:

@Test @Parameters(method = "parametersToTestAdd") public void whenWithNamedMethod_thenSafeAdd( int a, int b, int expectedValue) { assertEquals(expectedValue, serviceUnderTest.safeAdd(a, b)); } private Object[] parametersToTestAdd() { return new Object[] { new Object[] { 1, 2, 3 }, new Object[] { -10, 30, 20 }, new Object[] { Integer.MAX_VALUE, 2, Integer.MAX_VALUE }, new Object[] { Integer.MIN_VALUE, -8, Integer.MIN_VALUE } }; }

Il metodo di test viene annotato riguardo al metodo parametersToAdd () e recupera i parametri eseguendo il metodo di riferimento.

La specifica del metodo provider dovrebbe restituire un array di oggetti come risultato. Se un metodo con il nome specificato non è disponibile, lo scenario di test fallisce con l'errore:

java.lang.RuntimeException: Could not find method: bogusMethodName so no params were used.

5.3. Metodo mappato in base al nome del metodo di prova

Se non specifichiamo nulla nell'annotazione @Parameters , JUnitParams prova a caricare un metodo del fornitore di dati di prova in base al nome del metodo di prova. Il nome del metodo è costruito come "parametersFor" +:

@Test @Parameters public void whenWithnoParam_thenLoadByNameSafeAdd( int a, int b, int expectedValue) { assertEquals(expectedValue, serviceUnderTest.safeAdd(a, b)); } private Object[] parametersForWhenWithnoParam_thenLoadByNameSafe() { return new Object[] { new Object[] { 1, 2, 3 }, new Object[] { -10, 30, 20 }, new Object[] { Integer.MAX_VALUE, 2, Integer.MAX_VALUE }, new Object[] { Integer.MIN_VALUE, -8, Integer.MIN_VALUE } }; }

Nell'esempio precedente il nome del metodo di test è whenWithnoParam_shouldLoadByNameAbdSafeAdd () .

Pertanto, quando il metodo di prova viene eseguito, cerca un metodo del fornitore di dati con il nome parametersForWhenWithnoParam_shouldLoadByNameAbdSafeAdd () .

Poiché quel metodo esiste, caricherà i dati da esso ed eseguirà il test. Se non esiste un metodo di questo tipo che corrisponde al nome richiesto, il test fallisce come nell'esempio precedente.

5.4. Classe di test denominata definita all'interno dell'annotazione

Analogamente al modo in cui abbiamo fatto riferimento a un metodo del fornitore di dati in un esempio precedente, possiamo fare riferimento a una classe separata per fornire i dati per il nostro test:

@Test @Parameters(source = TestDataProvider.class) public void whenWithNamedClass_thenSafeAdd( int a, int b, int expectedValue) { assertEquals(expectedValue, serviceUnderTest.safeAdd(a, b)); } public class TestDataProvider { public static Object[] provideBasicData() { return new Object[] { new Object[] { 1, 2, 3 }, new Object[] { -10, 30, 20 }, new Object[] { 15, -5, 10 }, new Object[] { -5, -10, -15 } }; } public static Object[] provideEdgeCaseData() { return new Object[] { new Object[] { Integer.MAX_VALUE, 2, Integer.MAX_VALUE }, new Object[] { Integer.MIN_VALUE, -2, Integer.MIN_VALUE }, }; } }

Possiamo avere un numero qualsiasi di fornitori di dati di test in una classe dato che il nome del metodo inizia con "fornire". In tal caso, l'esecutore sceglie questi metodi e restituisce i dati.

Se nessun metodo di classe soddisfa tale requisito, anche se tali metodi restituiscono un array di oggetti , tali metodi verranno ignorati.

5.5. Utilizzando un file CSV

Possiamo utilizzare un file CSV esterno per caricare i dati del test. Ciò aiuta se il numero di casi di test possibili è piuttosto significativo o se i casi di test vengono modificati di frequente. Le modifiche possono essere eseguite senza influire sul codice di test.

Supponiamo di avere un file CSV con parametri di test come JunitParamsTestParameters.csv :

1,2,3 -10, 30, 20 15, -5, 10 -5, -10, -15

Ora vediamo come questo file può essere utilizzato per caricare i parametri di test nel metodo di test:

@Test @FileParameters("src/test/resources/JunitParamsTestParameters.csv") public void whenWithCsvFile_thenSafeAdd( int a, int b, int expectedValue) { assertEquals(expectedValue, serviceUnderTest.safeAdd(a, b)); }

Una limitazione di questo approccio è che non è possibile passare oggetti complessi. Sono valide solo le primitive e le String .

6. Conclusione

In questo tutorial, abbiamo esaminato come possiamo utilizzare le funzionalità di JUnitParams in poche parole.

Abbiamo anche coperto diversi approcci che la libreria ci fornisce per fornire parametri di test ai nostri metodi di test, ben oltre ciò che JUnit stesso può fare.

Come sempre, il codice sorgente può essere trovato su GitHub.