JUnit Test parametrizzato con esempio utilizzando @Parameters
โก Riepilogo intelligente
Test parametrizzati in JUnit Eseguire ripetutamente lo stesso metodo di test con diversi valori di input, in modo che un singolo metodo copra molti scenari. Le annotazioni @RunWith e @Parameters forniscono il set di dati per ogni iterazione.
Che cos'รจ un test parametrizzato in JUnit?
A test parametrizzato Si tratta di un test che esegue ripetutamente lo stesso metodo di test utilizzando valori diversi. Aiuta gli sviluppatori a risparmiare tempo nella scrittura di test che differiscono solo per gli input e i risultati attesi.
Utilizzando un test parametrizzato, รจ possibile impostare un metodo di test che recupera i dati da una sorgente dati. Questo lo rende la forma piรน semplice di test guidato dai dati disponibile all'interno JUnit da solo, senza bisogno di librerie esterne.
Consideriamo un semplice test che somma diversi numeri. Il codice potrebbe essere simile a questo:
L'approccio sopra descritto genera molta ridondanza. Ogni nuova coppia di numeri richiede un'ulteriore istruzione assert all'interno dello stesso metodo, e un errore nella prima asserzione nasconde tutte le asserzioni successive.
Serve un approccio piรน semplice. Utilizzando un test parametrizzato, รจ possibile aggiungere un singolo metodo che fornisca dieci input di dati e il test verrร eseguito automaticamente dieci volte.
Passaggi per creare un file con parametri JUnit Test
Il codice seguente mostra un esempio di test parametrizzato. Verifica il metodo sum() della classe Airthematic, che รจ la grafia utilizzata in tutto il progetto di esempio.
Passo 1) Crea una classe. In questo esempio, inseriremo due numeri utilizzando il metodo sum(int, int), che restituirร la somma dei numeri forniti.
Passo 2) Crea una classe di test parametrizzata.
Code Spiegazione
- Code Linea 11: Annota la tua classe di test usando @RunWith(Parameterized.class).
- Code Linea 13: Dichiarare la variabile "firstNumber" come privata e digitare come int.
- Code Linea 14: Dichiarazione della variabile 'secondNumber' come privata e di tipo int.
- Code Linea 15: Dichiarazione della variabile 'expectedResult' come privata e di tipo int.
- Code Linea 16: Dichiarazione della variabile 'airthematic' come privata e di tipo Airthematic.
@Corri con(class_name.class): il @Corri con L'annotazione viene utilizzata per specificare il nome della classe runner. Se non specifichiamo alcun tipo come parametro, il runtime sceglierร BloccareJUnit4ClassRunner per impostazione predefinita.
Questa classe รจ responsabile dell'esecuzione dei test con una nuova istanza di test. ร responsabile dell'invocazione JUnit metodi del ciclo di vita come setup (associa le risorse) e teardown (rilascia le risorse), che sono descritti nel JUnit dispositivo di prova tutorial.
Per parametrizzare, รจ necessario annotare la classe utilizzando @RunWith e passare il file .class richiesto per il test.
Passo 3) Crea un costruttore che memorizzi i dati di test. Memorizza 3 variabili.
Passo 4) Creare un metodo statico che generi e restituisca dati di test.
Code Linea 32,33: Creazione di un array bidimensionale (fornendo parametri di input per l'addizione). Utilizzando il metodo asList, convertiamo i dati in un tipo List, poichรฉ il tipo restituito dal metodo input รจ una Collection.
Code Linea 30: Usando il @Parametri annotazione per creare una serie di dati di input per eseguire il nostro test.
Il metodo statico identificato dall'annotazione @Parameters restituisce una Collection in cui ogni elemento della Collection sarร il dato di input per un'iterazione del test. Si consideri l'elemento {1,2,3}. Ecco:
- primoNumero = 1
- secondoNumero = 2
- Risultato atteso = 3
In questo caso, ogni elemento dell'array verrร passato al costruttore, uno alla volta, poichรฉ la classe viene istanziata piรน volte. I cinque array dichiarati nell'esempio producono quindi le seguenti cinque esecuzioni:
| Iterazione | primoNumero | secondoNumero | Risultato atteso | Linea console |
|---|---|---|---|---|
| [0] | 1 | 2 | 3 | Somma di Numbers = : 3 |
| [1] | 11 | 22 | 33 | Somma di Numbers = : 33 |
| [2] | 111 | 222 | 333 | Somma di Numbers = : 333 |
| [3] | 10 | 9 | 19 | Somma di Numbers = : 19 |
| [4] | 100 | 9 | 109 | Somma di Numbers = : 109 |
Passo 5) Il codice completo.
Code Spiegazione:
- Code Linea 25: Utilizzo dell'annotazione @Before per impostare le risorse (in questo caso Airthematic.class). L'annotazione @Before viene utilizzata per essere eseguita prima di ogni caso di test. Contiene la precondizione del test.
- Code Linea 36: Utilizziamo l'annotazione @Test per creare il nostro test.
- Code Linea 39: Creare un affermazione affermativa per verificare se la nostra somma รจ equivalente a quanto previsto.
Passo 6) Crea una classe di esecuzione dei test per eseguire il test parametrizzato:
Code Spiegazione:
- Code Linea 8: Dichiarando il metodo principale della classe Test che eseguirร il nostro JUnit test.
- Code Linea 9: Esecuzione dei casi di test utilizzando JUnitCore.runClasses, che accetta come parametro il nome della classe di test (nel nostro esempio utilizziamo AirthematicTest.class).
- Code Linea 11: Elaborazione del risultato tramite un ciclo for e stampa del risultato non riuscito.
- Code Linea 13: Stampa del risultato positivo.
Produzione:
Ecco l'output, che mostra un test riuscito senza errori. trace, come indicato di seguito. Nota che il JUnit La visualizzazione elenca una voce per riga di dati anzichรฉ un singolo test:
Visualizza il risultato sulla console, che mostra la somma dei due numeri:
Test parametrizzati in JUnit 5 con @ParameterizedTest
L'esempio sopra รจ scritto per JUnit 4. JUnit 5 (Jupiter) abbandona completamente il modello runner, quindi @RunWith(Parameterized.class), il costruttore di dati e i campi dell'istanza scompaiono tutti. Il JUnit 4 Il codice mostrato sopra non รจ obsoleto: funziona ancora invariato su JUnit Piattaforma tramite il motore vintage. I nuovi test, tuttavia, vengono normalmente scritti con @ParameterizedTest.
Sono necessarie due dipendenze: junit-jupiter-api per le annotazioni di test e parametri junit-jupiter per il supporto parametrizzato. Senza il secondo artefatto, le annotazioni della sorgente non verranno risolte affatto.
import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; class AirthematicTest { // one row per iteration, no constructor and no runner @ParameterizedTest(name = "{0} + {1} = {2}") @CsvSource({"1, 2, 3", "11, 22, 33", "111, 222, 333", "10, 9, 19", "100, 9, 109"}) void sumOfTwoNumbers(int firstNumber, int secondNumber, int expectedResult) { assertEquals(expectedResult, new Airthematic().sum(firstNumber, secondNumber)); } }
Giove offre diverse fonti di argomentazione, e quella giusta dipende dalla forma dei dati:
| Annotazione della fonte | Forniture | Usalo quando |
|---|---|---|
| @ValueSource | Una singola colonna di letterali | Il test accetta esattamente un argomento |
| @CsvSource | Righe separate da virgole in linea | Piccole tabelle di numeri e stringhe lette correttamente nel file |
| @CsvFileSource | Righe lette da un file CSV nel classpath di test | Il set di dati รจ di grandi dimensioni o gestito al di fuori del codice |
| @MethodSource | Una fabbrica statica che restituisce un flusso di argomenti | Sono necessari oggetti reali, valori calcolati o dati randomizzati |
| @EnumSource | Le costanti di un'enumerazione | Ogni valore dell'enumerazione deve essere esercitato |
Due regole mettono in difficoltร la maggior parte dei principianti. Un'annotazione di origine posizionata su un semplice metodo @Test viene silenziosamente ignorata, quindi il metodo deve contenere @ParameterizedTest. Inoltre, un valore vuoto non racchiuso tra virgolette in @CsvSource viene letto come null, mentre un valore vuoto racchiuso tra virgolette viene letto come stringa vuota.
Migliori JUnit 4 annotazioni utilizzate in questo articolo vengono mappate su Jupiter come segue: @RunWith(Parameterized.class) diventa @ParameterizedTest piรน un'annotazione di origine, @Parameters diventa @MethodSource o @CsvSource e @Before diventa @BeforeEach. L'elenco completo รจ trattato in JUnit annotazioni tutorial.
Vantaggi e limiti dei test parametrizzati
La parametrizzazione ha un costo. Elimina le duplicazioni, ma limita anche il modo in cui un test puรฒ essere scritto, quindi รจ importante conoscere entrambi gli aspetti prima di convertire una suite di test esistente.
Vantaggi
- Less duplicazione: Un metodo sostituisce un blocco di istruzioni assert quasi identiche, come mostrato nella prima schermata di questo articolo.
- Copertura piรน economica: L'aggiunta di un caso limite costa una riga di dati in piรน invece di un intero nuovo caso di prova metodo.
- Reportistica precisa: Ogni iterazione viene segnalata separatamente, quindi JUnit La visualizzazione identifica esattamente la riga che ha generato l'errore, anzichรฉ un errore aggregato.
- Dati centralizzati: Gli input risiedono in un singolo metodo e possono essere successivamente spostati in un file CSV o in una factory senza modificare le asserzioni.
limitazioni
- Una forma di affermazione: Ogni riga esegue le stesse asserzioni, quindi uno scenario che richiede controlli diversi necessita comunque di un proprio metodo di test.
- Ambito a livello di classe in JUnit 4: Il runner parametrizza l'intera classe, quindi anche i metodi @Test non correlati in quella classe vengono eseguiti una volta per riga.
- Rapporti illeggibili: Senza un modello di nome, gli errori vengono visualizzati come testAirthematicTest[3], che non dice nulla sui dati che si sono rotti.
- Dati inline voluminosi: Gli array di grandi dimensioni sovraccaricano la logica di test; spostali invece in un @CsvFileSource o in una factory @MethodSource.
Errori comuni in JUnit Test parametrizzati
La maggior parte degli errori parametrizzati sono errori di inizializzazione che si verificano prima dell'esecuzione di una singola asserzione. La tabella seguente elenca i messaggi che compaiono piรน frequentemente e le cause che li scatenano.
| Messaggio | Causare | Fissare |
|---|---|---|
| La classe di test deve avere esattamente un costruttore pubblico | La classe non dichiara alcun costruttore pubblico, oppure due di essi | Mantieni un costruttore pubblico i cui parametri corrispondano alle colonne di dati |
| Nessun metodo pubblico per i parametri statici sulla classe | Il metodo @Parameters non รจ pubblico statico oppure restituisce il tipo errato | Dichiaralo come pubblico statico Collection e restituisci Arrays.asList(โฆ) |
| IllegalArgumentException: numero di argomenti errato | Una riga รจ piรน larga o piรน stretta dell'elenco dei parametri del costruttore | Fai in modo che ogni array nella Collection abbia la stessa larghezza del costruttore |
| Errore di configurazione: nessun provider di argomenti | Un test Jupiter contiene @ParameterizedTest senza annotazione di origine | Aggiungi @ValueSource, @CsvSource, @CsvFileSource, @MethodSource o @EnumSource |
| L'annotazione della sorgente sembra non fare nulla | Il metodo รจ annotato con @Test invece di @ParameterizedTest | Sostituisci @Test con @ParameterizedTest e importa junit-jupiter-params |
Un'ulteriore trappola รจ lo stato condiviso. Perchรฉ JUnit crea una nuova istanza per riga, qualsiasi cosa contenuta in un campo statico sopravvive ad ogni iterazione e un valore scritto dalla riga [0] puรฒ modificare silenziosamente il risultato della riga [4]. Mantieni lo stato per riga nei campi dell'istanza e reimposta le risorse condivise nel metodo @Before o @BeforeEach. Le linee guida generali sull'isolamento dei test sono trattate in unit test tutorial.









