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: