JUnit Test parametrizat cu exemplu folosind @Parameters

⚡ Rezumat inteligent

Teste parametrizate în JUnit rulează aceeași metodă de testare în mod repetat cu valori de intrare diferite, astfel încât o metodă acoperă mai multe scenarii. Adnotările @RunWith și @Parameters furnizează setul de date pentru fiecare iterație.

  • 🔘 Sursa datelor: O metodă statică @Parameters returnează o colecție de matrice, iar fiecare matrice devine o iterație de test.
  • ☑️ Alergător: @RunWith(Parameterized.class) înlocuiește blocul implicitJUnit4ClassRunner și reconstruiește clasa o dată pe rând de date.
  • ✅ Constructor: Un constructor public stochează un singur rând de date în câmpurile instanței asupra cărora se afirmă metoda de testare.
  • 🧪 Exemplu lucrat: Cinci rânduri de intrare determină testul sum(), iar JUnit Vizualizați rapoartele. Rulează 5/5 cu zero erori.
  • 🛠️ JUnit 5: @ParameterizedTest cu @ValueSource, @CsvSource sau @MethodSource elimină atât runner-ul, cât și constructorul.
  • 📌 Capcanele: O metodă @Parameters nestatică, doi constructori publici sau o dependență junit-jupiter-params lipsă oprește rularea.

JUnit test parametrizat folosind adnotările @RunWith și @Parameters

Ce este un test parametrizat în JUnit?

A test parametrizat este un test care execută aceeași metodă de testare iar și iar, folosind valori diferite. Ajută dezvoltatorii să economisească timp atunci când scriu teste care diferă doar prin datele de intrare și rezultatele așteptate.

Folosind un test parametrizat, se poate configura o metodă de testare care preia date dintr-o anumită sursă de date. Aceasta îl face cea mai simplă formă de testare bazată pe date disponibil în interior JUnit în sine, fără a fi necesară o bibliotecă externă.

Luați în considerare un test simplu care însumează numere diferite. Codul ar putea arăta astfel:

JUnit metodă de testare care repetă trei apeluri assertEquals pentru metoda sum

Abordarea de mai sus duce la multă redundanță. Fiecare nouă pereche de numere necesită o altă instrucțiune de afirmare în cadrul aceleiași metode, iar o eroare la prima afirmație ascunde toate afirmațiile care o urmează.

Este nevoie de o abordare mai simplă. Folosind un test parametrizat, puteți adăuga o singură metodă care furnizează zece intrări de date, iar testul dvs. va rula automat de zece ori.

Pași pentru a crea un parametrizat JUnit Testare

Următorul cod prezintă un exemplu de test parametrizat. Acesta testează metoda sum() a clasei Airthematic, care este ortografia utilizată în întregul proiect exemplu.

Pas 1) Creați o clasă. În acest exemplu, vom introduce două numere folosind metoda sum(int, int), care va returna suma numerelor date.

Clasa Airthematic declară o metodă publică de sumă care adună două argumente de tip int

Pas 2) Creați o clasă de test parametrizată.

Antetul clasei de test adnotat cu @RunWith(Parameterized.class) și patru câmpuri private

Code Explicație

  • Code Linia 11: Adnotați clasa de test folosind @RunWith(Parameterized.class).
  • Code Linia 13: Declararea variabilei „firstNumber” ca private și tipul ca int.
  • Code Linia 14: Declararea variabilei „secondNumber” ca fiind privată și de tip int.
  • Code Linia 15: Declararea variabilei „expectedResult” ca fiind privată și de tip int.
  • Code Linia 16: Se declară variabila „airthematic” ca fiind privată și de tip Airthematic.

@Alearga cu(nume_clasă.clasă): the @Alearga cu adnotarea este utilizată pentru a specifica numele clasei de alergători. Dacă nu specificăm niciun tip ca parametru, timpul de execuție va alege BlocaJUnit4ClassRunner în mod implicit.

Această clasă este responsabilă pentru rularea testelor cu o nouă instanță de test. Este responsabilă pentru invocarea JUnit metodele ciclului de viață, cum ar fi configurarea (resursele asociate) și demontarea (lansarea resurselor), care sunt descrise în JUnit dispozitiv de testare tutorial.

Pentru a parametriza, trebuie să adnotați clasa folosind @RunWith și să transmiteți fișierul .class necesar pentru testare.

Pas 3) Creați un constructor care stochează datele de test. Acesta stochează 3 variabile.

Constructor de teste parametrizat care atribuie trei argumente de tip int câmpurilor de instanță

Pas 4) Creați o metodă statică care generează și returnează date de testare.

Metodă de intrare statică adnotată cu @Parameterized.Parameters care returnează o matrice de obiecte bidimensională

Code Linia 32,33: Crearea unui tablou bidimensional (furnizarea parametrilor de intrare pentru adunare). Folosind metoda asList convertim datele într-un tip List, deoarece tipul returnat de metoda de intrare este o Colecție.

Code Linia 30: Utilizarea @Parametrii adnotare pentru a crea un set de date de intrare pentru a rula testul nostru.

Metoda statică identificată de adnotarea @Parameters returnează o Colecție unde fiecare intrare din Colecție va fi data de intrare pentru o iterație a testului. Luați în considerare elementul {1,2,3}. Iată:

  • primulNumăr = 1
  • al doileaNumăr = 2
  • RezultatAșteptat = 3

Aici, fiecare element al tabloului va fi transmis constructorului, pe rând, deoarece clasa este instanțiată de mai multe ori. Prin urmare, cele cinci tablouri declarate în exemplu produc următoarele cinci execuții:

Repetare primulNumăr secondNumber Rezultat așteptat Linia de consolă
[0] 1 2 3 Suma de Numbers = : 3
[1] 11 22 33 Suma de Numbers = : 33
[2] 111 222 333 Suma de Numbers = : 333
[3] 10 9 19 Suma de Numbers = : 19
[4] 100 9 109 Suma de Numbers = : 109

Pas 5) Codul complet.

Listare completă AirthematicTest cu importuri, constructor, metoda @Parameters și metoda @Test

Code Explicaţie:

  • Code Linia 25: Se utilizează adnotarea @Before pentru configurarea resurselor (Airthematic.class aici). Adnotarea @Before este utilizată aici pentru a rula înaintea fiecărui caz de testare. Aceasta conține precondiția testului.
  • Code Linia 36: Folosind adnotarea @Test pentru a crea testul nostru.
  • Code Linia 39: Crearea unui declarație afirmativă pentru a verifica dacă suma noastră este echivalentă cu ceea ce ne așteptam.

Pas 6) Creați o clasă de testare pentru a rula testul parametrizat:

Clasa TestRunner transmite AirthematicTest.class către JUnitCore.runClasses și erori de imprimare

Code Explicaţie:

  • Code Linia 8: Declararea metodei principale a clasei Test care va rula metoda noastră JUnit Test.
  • Code Linia 9: Executarea cazurilor de testare folosind JUnitCore.runClasses, care primește numele clasei de test ca parametru (în exemplul nostru folosim AirthematicTest.class).
  • Code Linia 11: Procesarea rezultatului folosind o buclă for și afișarea rezultatului eșuat.
  • Code Linia 13: Imprimarea rezultatului de succes.

ieșire:

Iată rezultatul, care arată un test reușit fără eșecuri trace, așa cum este indicat mai jos. Rețineți că JUnit vizualizarea listează o intrare per rând de date în loc de un singur test:

Eclipse JUnit Vizualizare raportare Rulează 5/5 cu 0 erori și 0 eșecuri pentru clasa parametrizată

Vedeți rezultatul în consolă, care arată adunarea celor două numere:

Eclipse consolă imprimând o sumă de Numbers linie pentru fiecare dintre cele cinci rânduri de parametri

Teste parametrizate în JUnit 5 cu @ParameterizedTest

Exemplul de mai sus este scris pentru JUnit 4. JUnit 5 (Jupiter) elimină complet modelul de alergător, astfel încât @RunWith(Parameterized.class), constructorul de date și câmpurile de instanță dispar toate. JUnit Codul 4 prezentat mai sus nu este învechit: acesta rulează în continuare neschimbat pe JUnit Platformă prin intermediul motorului vintage. Testele noi, însă, sunt de obicei scrise cu @ParameterizedTest.

Sunt necesare două dependențe: junit-jupiter-api pentru adnotările de test și junit-jupiter-parametri pentru suportul parametrizat. Fără al doilea artefact, adnotările sursă nu se vor rezolva deloc.

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));
    }
}

Jupiter oferă mai multe surse de argumente, iar cea corectă depinde de forma datelor:

Adnotare sursă Furnituri Folosește-l când
@ValueSource O singură coloană de literali Testul acceptă doar un argument
@CsvSource Rânduri separate prin virgulă în linie Tabele mici de numere și șiruri de caractere se citesc curat în fișier
@CsvFileSource Rânduri citite dintr-un fișier CSV pe calea de clasă de testare Setul de date este mare sau este menținut în afara codului
@MethodSource O fabrică statică care returnează un flux de argumente Sunt necesare obiecte reale, valori calculate sau date aleatorii
@EnumSource Constantele unei enumări Fiecare valoare enum trebuie exercitată

Două reguli sunt potrivite pentru majoritatea începătorilor. O adnotare sursă plasată pe o metodă @Test simplă este ignorată silențios, deci metoda trebuie să conțină @ParameterizedTest. Iar o valoare goală neîncadrată între ghilimele din @CsvSource este citită ca nulă, în timp ce o valoare goală între ghilimele este citită ca un șir gol.

JUnit 4 adnotări utilizate în acest articol se mapează pe Jupiter după cum urmează: @RunWith(Parameterized.class) devine @ParameterizedTest plus o adnotare sursă, @Parameters devine @MethodSource sau @CsvSource, iar @Before devine @BeforeEach. Lista completă este prezentată în JUnit adnotări tutorial.

Avantajele și limitele testelor parametrizate

Parametrizarea nu este gratuită. Elimină duplicarea, dar limitează și modul în care poate fi scris un test, așa că merită să cunoașteți ambele părți înainte de a converti o suită existentă.

Avantaje

  • Less duplicare: O metodă înlocuiește un bloc de instrucțiuni de afirmare aproape identice, așa cum arată prima captură de ecran din acest articol.
  • Acoperire mai ieftină: Adăugarea unui caz limită costă încă un rând de date în loc de un rând complet nou. caz de testare metodă.
  • Raportare precisă: Fiecare iterație este raportată separat, astfel încât JUnit Vizualizarea identifică exact ce rând a eșuat, mai degrabă decât o singură eroare agregată.
  • Date centralizate: Intrările se află într-o singură metodă și pot fi mutate ulterior într-un fișier CSV sau într-o fabrică fără a atinge aserțiunile.

Limitări

  • O formă de afirmație: Fiecare rând rulează aceleași aserțiuni, deci un scenariu care necesită verificări diferite are nevoie în continuare de propria metodă de testare.
  • Domeniu de aplicare la nivel de clasă în JUnit 4: Runner-ul parametrizează întreaga clasă, astfel încât metodele @Test fără legătură din acea clasă rulează și ele o dată pe rând.
  • Rapoarte ilizibile: Fără un șablon de nume, erorile apar ca testAirthematicTest[3], care nu spune nimic despre datele care au generat erori.
  • Date inline voluminoase: Matricele mari aglomerează logica de testare; mutați-le în @CsvFileSource sau într-o fabrică @MethodSource în schimb.

Erori frecvente în JUnit Teste parametrizate

Majoritatea erorilor parametrizate sunt erori de inițializare generate înainte de executarea unei singure aserțiuni. Tabelul de mai jos listează mesajele care apar cel mai des și ce le declanșează.

Mesaj Provoca Repara
Clasa de test ar trebui să aibă exact un constructor public Clasa nu declară niciun constructor public sau doi dintre ei Păstrați un constructor public ai cărui parametri se potrivesc cu coloanele de date
Nicio metodă publică cu parametri statici în clasă Metoda @Parameters nu este public static sau returnează tipul greșit Declară-o ca o colecție public static și returnează Arrays.asList(…)
ExcepțieArgumentIllegal: număr greșit de argumente Un rând este mai lat sau mai îngust decât lista de parametri a constructorului Faceți ca fiecare matrice din Colecție să aibă aceeași lățime ca și constructorul
Eroare de configurare: fără furnizor de argumente Un test Jupiter poartă @ParameterizedTest fără adnotare sursă Adăugați @ValueSource, @CsvSource, @CsvFileSource, @MethodSource sau @EnumSource
Adnotarea sursă pare să nu facă nimic Metoda este adnotată @Test în loc de @ParameterizedTest Înlocuiți @Test cu @ParameterizedTest și importați junit-jupiter-params

O altă capcană este starea partajată. Deoarece JUnit construiește o nouă instanță pe rând, orice conținut dintr-un câmp static supraviețuiește fiecărei iterații, iar o valoare scrisă de rândul [0] poate schimba discret rezultatul rândului [4]. Păstrează starea pe rând în câmpurile instanței și resetează resursele partajate în metoda @Before sau @BeforeEach. Îndrumări generale privind izolarea testelor sunt prezentate în testarea unitara tutorial.

Întrebări frecvente

TestNG furnizează rânduri printr-o metodă @DataProvider la care se face referire per metodă de testare, astfel încât testele fără legătură din clasă nu sunt afectate. JUnit 4 parametrizează întreaga clasă prin intermediul runner-ului său. JUnit 5 acoperă această diferență cu @ParameterizedTest per metodă.

Da. JUnit 4 acceptă @Parameters(name = “{index}: sum({0},{1})={2}”) și Jupiter acceptă @ParameterizedTest(name = “…”). Substituenții sunt înlocuiți în timpul execuției, astfel încât un raport de eroare denumește rândul în cauză în loc să afișeze un index simplu.

Da. JUnit Versiunea 4 acceptă @Parameter(0) și @Parameter(1) pe câmpuri publice nestatice, iar clasa se bazează apoi pe constructorul implicit. Combinarea injectării de câmpuri cu un constructor de date declanșează eroarea exact-one-public-constructor.

JUnit 4 are nevoie doar de artefactul junit, deoarece rulerul parametrizat este livrat în interiorul acestuia. JUnit 5 necesită junit-jupiter-params alături de junit-jupiter-api; fără acest artefact, @ParameterizedTest și fiecare adnotare sursă nu se rezolvă.

Jupiter oferă @CsvFileSource(resources = “/data.csv”, numLinesToSkip = 1), care citește rânduri din calea de clasă de test. JUnit 4 nu are un echivalent încorporat, așadar metoda @Parameters trebuie să deschidă și să analizeze fișierul în sine înainte de a returna Colecția.

In JUnit 4 se poate, dar runner-ul parametrizează întreaga clasă, astfel încât fiecare metodă rulează o dată pe rând de date. Jupiter parametrizează metode individuale, astfel încât metodele simple @Test din aceeași clasă se execută exact o singură dată.

Asistenții inteligenți artificiali citesc semnătura unei metode și propun rânduri limită, cum ar fi intrări zero, negative, maxime și depășire, pe care un tabel scris de mână le omite adesea. Revvizualizați fiecare rezultat așteptat generat, deoarece un model poate produce un rând plauzibil cu răspunsul greșit.

Copilotul GitHub produce schela rapid, dar adesea amestecă JUnit 4 și importurile Jupiter, iar uneori lasă o adnotare sursă pe o metodă @Test simplă. Verificați importurile înainte de a rula suita.

Rezumați această postare cu: