JUnit Parametrizovaný test s příkladem pomocí @Parameters
⚡ Chytré shrnutí
Parametrizované testy v JUnit Spouštět stejnou testovací metodu opakovaně s různými vstupními hodnotami, takže jedna metoda pokrývá mnoho scénářů. Anotace @RunWith a @Parameters poskytují datovou sadu pro každou iteraci.
Co je parametrizovaný test v JUnit?
A parametrizovaný test je test, který opakovaně spouští stejnou testovací metodu s různými hodnotami. Pomáhá vývojářům ušetřit čas při psaní testů, které se liší pouze vstupy a očekávanými výsledky.
Pomocí parametrizovaného testu lze nastavit testovací metodu, která načítá data z nějakého zdroje dat. Díky tomu je to nejjednodušší forma testování řízené daty k dispozici uvnitř JUnit sám o sobě, bez nutnosti externí knihovny.
Uvažujme jednoduchý test, který sčítá různá čísla. Kód může vypadat takto:
Výše uvedený přístup vede k velké redundanci. Každá nová dvojice čísel potřebuje další assert příkaz v rámci stejné metody a selhání prvního assertu skryje všechny asserty, které za ním následují.
Je potřeba jednodušší přístup. Pomocí parametrizovaného testu můžete přidat jednu metodu, která poskytuje deset datových vstupů, a váš test se automaticky spustí desetkrát.
Kroky k vytvoření parametrizovaného JUnit test
Následující kód ukazuje příklad parametrizovaného testu. Testuje metodu sum() třídy Airthematic, což je pravopis používaný v celém ukázkovém projektu.
Krok 1) Vytvořte třídu. V tomto příkladu zadáme dvě čísla pomocí metody sum(int, int), která vrátí součet zadaných čísel.
Krok 2) Vytvořte parametrizovanou testovací třídu.
Code Vysvětlení
- Code Řádek 11: Anotujte svou testovací třídu pomocí @RunWith(Parameterized.class).
- Code Řádek 13: Deklarování proměnné 'firstNumber' jako soukromé a typu jako int.
- Code Řádek 14: Deklarace proměnné 'secondNumber' jako private a typ int.
- Code Řádek 15: Deklarace proměnné 'expectedResult' jako private a typ int.
- Code Řádek 16: Deklarace proměnné 'airthematic' jako soukromé a typ jako Airthematic.
@RunWith(název_třídy.třída): ta @RunWith Anotace se používá k určení názvu třídy běžce. Pokud nezadáme žádný typ jako parametr, běhové prostředí si vybere BlokovatJUnit4ClassRunner ve výchozím stavu.
Tato třída je zodpovědná za spouštění testů s novou instancí testu. Je zodpovědná za volání JUnit metody životního cyklu, jako je nastavení (přidružení zdrojů) a demontáž (uvolnění zdrojů), které jsou popsány v JUnit zkušební přípravek výukový program.
Pro parametrizaci je potřeba třídu anotovat pomocí @RunWith a předat požadovanou třídu .class, která má být testována.
Krok 3) Vytvořte konstruktor, který ukládá testovací data. Ukládá 3 proměnné.
Krok 4) Vytvořte statickou metodu, která generuje a vrací testovací data.
Code Řádek 32,33: Vytvoření dvourozměrného pole (s poskytnutím vstupních parametrů pro sčítání). Pomocí metody asList převedeme data do typu List, protože návratový typ vstupní metody je Collection.
Code Řádek 30: Za použití @Parametry anotace k vytvoření sady vstupních dat pro spuštění našeho testu.
Statická metoda identifikovaná anotací @Parameters vrací kolekci (Collection), kde každý záznam v kolekci bude vstupními daty pro jednu iteraci testu. Uvažujme prvek {1,2,3}. Zde:
- prvníČíslo = 1
- druhéČíslo = 2
- očekávanýVýsledek = 3
Zde bude každý prvek pole předán konstruktoru, jeden po druhém, protože třída je instancována několikrát. Pět polí deklarovaných v příkladu proto vygeneruje následujících pět běhů:
| Opakování | prvníČíslo | druhéČíslo | očekávanýVýsledek | Konzolová linka |
|---|---|---|---|---|
| 1 | 2 | 3 | Součet Numbers = : 3 | |
| 11 | 22 | 33 | Součet Numbers = : 33 | |
| 111 | 222 | 333 | Součet Numbers = : 333 | |
| 10 | 9 | 19 | Součet Numbers = : 19 | |
| 100 | 9 | 109 | Součet Numbers = : 109 |
Krok 5) Kompletní kód.
Code Vysvětlení:
- Code Řádek 25: Použití anotace @Before k nastavení zdrojů (zde Airthematic.class). Anotace @Before se zde používá ke spuštění před každým testovacím případem. Obsahuje předběžnou podmínku testu.
- Code Řádek 36: Použití anotace @Test k vytvoření našeho testu.
- Code Řádek 39: Vytvoření prohlášení o tvrzení abychom ověřili, zda je náš součet ekvivalentní tomu, co jsme očekávali.
Krok 6) Vytvořte třídu test runner pro spuštění parametrizovaného testu:
Code Vysvětlení:
- Code Řádek 8: Deklarace hlavní metody třídy Test, která spustí náš JUnit test.
- Code Řádek 9: Spuštění testovacích případů pomocí JUnitCore.runClasses, který jako parametr bere název testovací třídy (v našem příkladu používáme AirthematicTest.class).
- Code Řádek 11: Zpracování výsledku pomocí smyčky for a výpis neúspěšného výsledku.
- Code Řádek 13: Vytiskněte úspěšný výsledek.
Výstup:
Zde je výstup, který ukazuje úspěšný test bez selhání. trace, jak je uvedeno níže. Všimněte si, že JUnit zobrazení uvádí jeden záznam na řádek dat, nikoli jeden test:
Podívejte se na výsledek v konzoli, který ukazuje součet dvou čísel:
Parametrizované testy v JUnit 5 s @ParameterizedTest
Výše uvedený příklad je napsán pro JUnit 4. JUnit 5 (Jupiter) zcela ruší model běžce, takže @RunWith(Parameterized.class), konstruktor dat a pole instance zmizí. JUnit 4 kód uvedený výše není zastaralý: stále běží beze změny na JUnit Platforma přes vintage engine. Nové testy se však obvykle píší s @ParameterizedTest.
Jsou vyžadovány dvě závislosti: junit-jupiter-api pro anotace testů a junit-jupiter-params pro parametrizovanou podporu. Bez druhého artefaktu se anotace zdroje vůbec nevyřeší.
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 nabízí několik zdrojů argumentů a ten správný závisí na tvaru dat:
| Anotace zdroje | Dodávky | Použijte to, když |
|---|---|---|
| @ValueSource | Jeden sloupec literálů | Test bere přesně jeden argument |
| @CsvSource | Vložené řádky oddělené čárkami | Malé tabulky čísel a řetězců se v souboru čtou čistě |
| @CsvFileSource | Řádky načtené z CSV v testovací cestě tříd | Datová sada je velká nebo je udržována mimo kód. |
| @MethodSource | Statická továrna vracející proud argumentů | Jsou potřeba reálné objekty, vypočítané hodnoty nebo randomizovaná data |
| @EnumSource | Konstanty výčtu | Každá hodnota výčtu musí být vykonávána |
Většinu začátečníků zaujmou dvě pravidla. Anotace zdroje umístěná v prosté metodě @Test je tiše ignorována, takže metoda musí obsahovat @ParameterizedTest. A prázdná hodnota bez uvozovek v @CsvSource je čtena jako null, zatímco prázdná hodnota v uvozovkách je čtena jako prázdný řetězec.
Jedno JUnit 4 anotace použité v tomto článku se mapují na Jupiter takto: @RunWith(Parameterized.class) se změní na @ParameterizedTest plus anotaci zdroje, @Parameters se změní na @MethodSource nebo @CsvSource a @Before se změní na @BeforeEach. Úplný seznam je uveden v JUnit anotace výukový program.
Výhody a omezení parametrizovaných testů
Parametrizace není zdarma. Odstraňuje duplicitu, ale také omezuje způsob, jakým lze test napsat, takže je vhodné znát obě strany před převodem existující sady.
Výhody
- Less zdvojení: Jedna metoda nahrazuje blok téměř identických assert příkazů, jak ukazuje první snímek obrazovky v tomto článku.
- Levnější krytí: Přidání okrajového případu stojí jeden datový řádek navíc místo zcela nového. modelový případ metoda.
- Přesné hlášení: Každá iterace je hlášena samostatně, takže JUnit zobrazení přesně identifikuje, který řádek selhal, a nikoli jedno agregované selhání.
- Centralizovaná data: Vstupy jsou uloženy v jedné metodě a později je lze přesunout do souboru CSV nebo továrny, aniž by se musely měnit aserce.
Omezení
- Jeden tvar tvrzení: Každý řádek spouští stejná tvrzení, takže scénář, který vyžaduje různé kontroly, stále potřebuje vlastní testovací metodu.
- Rozsah na úrovni třídy v JUnit 4: Běžec parametrizuje celou třídu, takže nesouvisející metody @Test v dané třídě se také spustí jednou na řádek.
- Nečitelné zprávy: Bez šablony názvu se selhání zobrazují jako testAirthematicTest[3], což neříká nic o datech, která se poškodila.
- Objemná vložená data: Velká pole vytěsňují testovací logiku; přesuňte je raději do @CsvFileSource nebo do továrny @MethodSource.
Časté chyby v JUnit Parametrizované testy
Většina parametrizovaných selhání jsou inicializační chyby vyvolané před provedením jediného aserčního výrazu. Níže uvedená tabulka uvádí zprávy, které se objevují nejčastěji, a co je spouští.
| Zpráva | Způsobit | Opravit |
|---|---|---|
| Testovací třída by měla mít právě jeden veřejný konstruktor | Třída nedeklaruje žádný veřejný konstruktor, nebo alespoň dva. | Ponechte jeden veřejný konstruktor, jehož parametry odpovídají datovým sloupcům. |
| Žádná metoda veřejných statických parametrů ve třídě | Metoda @Parameters není public static nebo vrací nesprávný typ. | Deklarujte ji jako public static Collection a vraťte Arrays.asList(…) |
| IllegalArgumentException: nesprávný počet argumentů | Řádek je širší nebo užší než seznam parametrů konstruktoru. | Nastavte každé pole v kolekci na stejnou šířku jako konstruktor. |
| Chyba konfigurace: žádný poskytovatel argumentů | Jupiterův test obsahuje @ParameterizedTest bez anotace zdroje. | Přidejte @ValueSource, @CsvSource, @CsvFileSource, @MethodSource nebo @EnumSource |
| Zdá se, že anotace zdroje nic nedělá. | Metoda je označena jako @Test místo @ParameterizedTest. | Nahraďte @Test za @ParameterizedTest a importujte junit-jupiter-params |
Další pastí je sdílený stav. Protože JUnit vytváří novou instanci pro každý řádek, cokoli obsažené ve statickém poli přežije každou iteraci a hodnota zapsaná v řádku [0] může nenápadně změnit výsledek řádku [4]. Zachovávejte stav pro každý řádek v polích instance a resetujte sdílené zdroje v metodě @Before nebo @BeforeEach. Obecné pokyny k izolaci testů jsou uvedeny v testování jednotky výukový program.









