JUnit Parametrirani test s primjerom pomoću @Parameters
⚡ Pametni sažetak
Parametrizirani testovi u JUnit Ponavljajte istu metodu testiranja s različitim ulaznim vrijednostima, tako da jedna metoda pokriva mnoge scenarije. Anotacije @RunWith i @Parameters daju skup podataka za svaku iteraciju.
Što je parametrizirani test u JUnit?
A parametrizirani test je test koji izvršava istu metodu testiranja iznova i iznova koristeći različite vrijednosti. Pomaže programerima da uštede vrijeme pri pisanju testova koji se razlikuju samo po ulaznim podacima i očekivanim rezultatima.
Korištenjem parametriziranog testa može se postaviti metoda testiranja koja dohvaća podatke iz nekog izvora podataka. To ga čini najjednostavnijim oblikom testiranje temeljeno na podacima dostupno unutra JUnit sam po sebi, bez potrebe za vanjskom bibliotekom.
Razmotrimo jednostavan test koji zbraja različite brojeve. Kod može izgledati ovako:
Gornji pristup dovodi do velike redundancije. Svaki novi par brojeva zahtijeva još jednu tvrdnju unutar iste metode, a neuspjeh prve tvrdnje skriva svaku tvrdnju koja slijedi nakon nje.
Potreban je jednostavniji pristup. Korištenjem parametriziranog testa možete dodati jednu metodu koja daje deset ulaznih podataka, a vaš će se test automatski pokrenuti deset puta.
Koraci za stvaranje parametriziranog JUnit test
Sljedeći kod prikazuje primjer parametriziranog testa. Testira metodu sum() klase Airthematic, što je pravopis koji se koristi u cijelom primjeru projekta.
Korak 1) Kreirajte klasu. U ovom primjeru, unesemo dva broja koristeći metodu sum(int, int), koja će vratiti zbroj zadanih brojeva.
Korak 2) Napravite parametriziranu testnu klasu.
Code Objašnjenje
- Code Redak 11: Označite svoju testnu klasu koristeći @RunWith(Parameterized.class).
- Code Redak 13: Proglašavanje varijable 'firstNumber' privatnom i tipa int.
- Code Redak 14: Deklarisanje varijable 'secondNumber' kao privatne i tip int.
- Code Redak 15: Deklariranje varijable 'expectedResult' kao privatne i tipa int.
- Code Redak 16: Deklarisanje varijable 'airthematic' kao privatne i tip kao Airthematic.
@RunWith(naziv_klase.klasa): the @RunWith Anotacija se koristi za određivanje naziva klase izvršavanja. Ako ne navedemo nijedan tip kao parametar, runtime će odabrati BlokiratiJUnit4ClassRunner prema zadanim postavkama.
Ova klasa je odgovorna za pokretanje testova s novom testnom instancom. Odgovorna je za pozivanje JUnit metode životnog ciklusa kao što su postavljanje (povezivanje resursa) i rastavljanje (objavljivanje resursa), koje su opisane u JUnit ispitni uređaj udžbenik.
Za parametrizaciju, potrebno je označiti klasu pomoću @RunWith i proslijediti potrebnu .class za testiranje.
Korak 3) Napravite konstruktor koji pohranjuje testne podatke. Pohranjuje 3 varijable.
Korak 4) Stvorite statičku metodu koja generira i vraća testne podatke.
Code Redak 32,33: Izrada dvodimenzionalnog niza (davanje ulaznih parametara za zbrajanje). Korištenjem metode asList pretvaramo podatke u tip List, budući da je povratni tip ulazne metode Kolekcija.
Code Redak 30: Korištenje @Parametri napomenu za stvaranje skupa ulaznih podataka za izvođenje našeg testa.
Statička metoda identificirana anotacijom @Parameters vraća kolekciju gdje će svaki unos u kolekciji biti ulazni podatak za jednu iteraciju testa. Razmotrimo element {1,2,3}. Ovdje:
- prviBroj = 1
- drugiBroj = 2
- očekivaniRezultat = 3
Ovdje će se svaki element niza proslijediti konstruktoru, jedan po jedan, jer se klasa instancira više puta. Pet nizova deklariranih u primjeru stoga proizvode sljedećih pet izvršavanja:
| ponavljanje | prviBroj | drugiBroj | očekivani rezultat | Konzolna linija |
|---|---|---|---|---|
| [0] | 1 | 2 | 3 | Zbroj Numbers = : 3 |
| [1] | 11 | 22 | 33 | Zbroj Numbers = : 33 |
| [2] | 111 | 222 | 333 | Zbroj Numbers = : 333 |
| [3] | 10 | 9 | 19 | Zbroj Numbers = : 19 |
| [4] | 100 | 9 | 109 | Zbroj Numbers = : 109 |
Korak 5) Potpuni kod.
Code Objašnjenje:
- Code Redak 25: Korištenje anotacije @Before za postavljanje resursa (ovdje Airthematic.class). Anotacija @Before se ovdje koristi za pokretanje prije svakog testnog slučaja. Sadrži preduvjet testa.
- Code Redak 36: Korištenje anotacije @Test za izradu našeg testa.
- Code Redak 39: Stvaranje tvrdnja kako bismo provjerili je li naš zbroj jednak onome što smo očekivali.
Korak 6) Napravite klasu za pokretanje parametriziranog testa:
Code Objašnjenje:
- Code Redak 8: Deklarisanje glavne metode klase Test koja će pokrenuti naš JUnit Test.
- Code Redak 9: Izvršavanje testnih slučajeva pomoću JUnitCore.runClasses, koji kao parametar uzima naziv testne klase (u našem primjeru koristimo AirthematicTest.class).
- Code Redak 11: Obrada rezultata pomoću for petlje i ispis neuspješnog rezultata.
- Code Redak 13: Ispis uspješnog rezultata.
Izlaz:
Evo rezultata koji pokazuje uspješan test bez greške trace, kao što je navedeno u nastavku. Imajte na umu da JUnit prikaz navodi jedan unos po retku podataka umjesto jednog testa:
Pogledajte rezultat na konzoli, koji prikazuje zbrajanje dvaju brojeva:
Parametrizirani testovi u JUnit 5 s @ParameterizedTest
Gornji primjer je napisan za JUnit 4. JUnit 5 (Jupiter) potpuno izostavlja model trkača, tako da @RunWith(Parameterized.class), konstruktor podataka i polja instance nestaju. JUnit 4 prikazani kod nije zastario: još uvijek se izvršava nepromijenjen na JUnit Platforma putem vintage engine-a. Novi testovi se, međutim, obično pišu s @ParameterizedTest.
Potrebne su dvije ovisnosti: junit-jupiter-api za testne anotacije i junit-jupiter-params za parametriziranu podršku. Bez drugog artefakta, izvorne anotacije se uopće neće riješiti.
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 nudi nekoliko izvora argumenata, a pravi ovisi o obliku podataka:
| Izvorna napomena | Zalihe | Koristite ga kada |
|---|---|---|
| @ValueSource | Jedan stupac literala | Test uzima točno jedan argument |
| @CsvSource | Ugrađeni retci odvojeni zarezima | Male tablice brojeva i nizova znakova jasno se čitaju u datoteci |
| @CsvFileSource | Redci pročitani iz CSV-a na testnoj klasnoj putanji | Skup podataka je velik ili se održava izvan koda |
| @MethodSource | Statička tvornica koja vraća tok argumenata | Potrebni su stvarni objekti, izračunate vrijednosti ili randomizirani podaci |
| @EnumSource | Konstante nabrajanja | Svaka vrijednost nabrajanja mora se izvršiti |
Dva pravila hvataju većinu početnika. Anotacija izvora postavljena na običnu @Test metodu se tiho ignorira, pa metoda mora nositi @ParameterizedTest. Prazna vrijednost bez navodnika u @CsvSource se čita kao null, dok se prazna vrijednost pod navodnicima čita kao prazan niz.
The JUnit 4 anotacije korištene u ovom članku preslikavaju se na Jupiter na sljedeći način: @RunWith(Parameterized.class) postaje @ParameterizedTest plus anotacija izvora, @Parameters postaje @MethodSource ili @CsvSource, a @Before postaje @BeforeEach. Potpuni popis nalazi se u JUnit bilješke udžbenik.
Prednosti i ograničenja parametriziranih testova
Parametrizacija nije besplatna. Uklanja dupliciranje, ali i ograničava način pisanja testa, stoga je vrijedno znati obje strane prije pretvaranja postojećeg paketa.
Prednosti
- Less dupliciranje: Jedna metoda zamjenjuje blok gotovo identičnih assert naredbi, kao što prikazuje prva snimka zaslona u ovom članku.
- Jeftinije pokriće: Dodavanje rubnog slučaja košta još jedan redak podataka umjesto cijelog novog testni slučaj metoda.
- Precizno izvještavanje: Svaka iteracija se izvještava zasebno, tako da JUnit prikaz točno identificira koji je redak bio neuspješan, a ne jedan agregirani neuspjeh.
- Centralizirani podaci: Ulazi se nalaze u jednoj metodi i kasnije se mogu premjestiti u CSV datoteku ili tvornicu bez dodirivanja tvrdnji.
Ograničenja
- Jedan oblik tvrdnje: Svaki redak izvršava iste tvrdnje, tako da scenarij koji zahtijeva različite provjere i dalje zahtijeva vlastitu metodu testiranja.
- Opseg na razini klase u JUnit 4: Izvršitelj parametrizira cijelu klasu, tako da se nepovezane @Test metode u toj klasi također izvršavaju jednom po retku.
- Nečitljiva izvješća: Bez predloška imena, kvarovi se prikazuju kao testAirthematicTest[3], što ne govori ništa o podacima koji su se pokvarili.
- Obimni inline podaci: Veliki nizovi istiskuju logiku testiranja; umjesto toga, premjestite ih u @CsvFileSource ili tvornicu @MethodSource.
Uobičajene pogreške u JUnit Parametrizirani testovi
Većina parametriziranih kvarova su inicijalizacijske pogreške koje se javljaju prije izvršavanja jedne tvrdnje. Tablica u nastavku navodi poruke koje se najčešće pojavljuju i što ih pokreće.
| Poruka | Izazvati | Popraviti |
|---|---|---|
| Testna klasa treba imati točno jedan javni konstruktor | Klasa ne deklarira niti jedan javni konstruktor, ili čak dva. | Zadržite jedan javni konstruktor čiji parametri odgovaraju stupcima podataka |
| Nema javne metode statičkih parametara na klasi | Metoda @Parameters nije javna statička ili vraća pogrešan tip. | Deklarirajte je kao javnu statičku kolekciju i vratite Arrays.asList(…) |
| IllegalArgumentException: pogrešan broj argumenata | Red je širi ili uži od popisa parametara konstruktora | Neka svaki niz u kolekciji bude iste širine kao i konstruktor |
| Pogreška konfiguracije: nema pružatelja argumenata | Jupiter test nosi @ParameterizedTest bez napomene o izvoru | Dodajte @ValueSource, @CsvSource, @CsvFileSource, @MethodSource ili @EnumSource |
| Čini se da izvorna napomena ne radi ništa | Metoda je označena s @Test umjesto @ParameterizedTest | Zamijenite @Test s @ParameterizedTest i uvozite junit-jupiter-params |
Još jedna zamka je dijeljeno stanje. Jer JUnit gradi novu instancu po retku, sve što se nalazi u statičkom polju preživi svaku iteraciju, a vrijednost koju zapisuje redak [0] može tiho promijeniti ishod retka [4]. Zadržite stanje po retku u poljima instance i resetirajte dijeljene resurse u metodi @Before ili @BeforeEach. Opće smjernice o izoliranju testova obuhvaćene su u ispitivanje jedinice udžbenik.









