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.

  • 🔘 Zdroj dat: Statická metoda @Parameters vrací kolekci polí a každé pole se stává jednou testovací iterací.
  • ☑️ Běžec: @RunWith(Parameterized.class) nahrazuje výchozí blokJUnit4ClassRunner a znovu sestaví třídu jednou pro každý řádek dat.
  • (Tj. Stavitel: Jeden veřejný konstruktor ukládá jeden řádek dat do polí instance, proti kterým testovací metoda provádí assert.
  • 🧪 Zpracovaný příklad: Pět vstupních řádků řídí test sum() a JUnit zobrazit zprávy Běží 5/5 s nulovými chybami.
  • 🛠️ JUnit 5: @ParameterizedTest s @ValueSource, @CsvSource nebo @MethodSource odstraní běžec i konstruktor.
  • 📌 Úskalí: Nestatická metoda @Parameters, dva veřejné konstruktory nebo chybějící závislost junit-jupiter-params zastaví běh.

JUnit parametrizovaný test s použitím anotací @RunWith a @Parameters

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:

JUnit testovací metoda opakující tři volání metody assertEquals pro metodu sum

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.

Třída Airthematic deklarující veřejnou metodu sum, která sčítá dva celočíselné argumenty

Krok 2) Vytvořte parametrizovanou testovací třídu.

Záhlaví testovací třídy s anotací @RunWith(Parameterized.class) a čtyřmi privátními poli

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é.

Parametrický konstruktor testů přiřazující tři celočíselné argumenty polím instance

Krok 4) Vytvořte statickou metodu, která generuje a vrací testovací data.

Statická vstupní metoda s anotací @Parameterized.Parameters vracející dvourozměrné pole objektů

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.

Kompletní výpis AirthematicTest s importy, konstruktorem, metodou @Parameters a metodou @Test

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:

Třída TestRunner předává třídě AirthematicTest.class JUnitCore.runClasses a selhání tisku

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:

Eclipse JUnit zobrazení reportingu Spuštěno 5/5 s 0 chybami a 0 selháními pro parametrizovanou třídu

Podívejte se na výsledek v konzoli, který ukazuje součet dvou čísel:

Eclipse konzolový výpis jedné Součet Numbers řádek pro každý z pěti řádků parametrů

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.

Nejčastější dotazy

TestNG dodává řádky prostřednictvím metody @DataProvider, na kterou se odkazuje každá testovací metoda, takže nesouvisející testy ve třídě nejsou ovlivněny. JUnit 4 parametrizuje celou třídu prostřednictvím svého běžce. JUnit 5 tuto mezeru uzavírá pomocí @ParameterizedTest pro každou metodu.

Ano. JUnit 4 akceptuje @Parameters(name = “{index}: sum({0},{1})={2}”) a Jupiter akceptuje @ParameterizedTest(name = “…”). Zástupné symboly jsou nahrazovány za běhu, takže selhání pojmenuje problematický řádek místo zobrazení holého indexu.

Ano. JUnit Verze 4 podporuje @Parameter(0) a @Parameter(1) na veřejných nestatických polích a třída se pak spoléhá na výchozí konstruktor. Kombinace vkládání polí s konstruktorem dat spouští chybu exactly-one-public-constructor.

JUnit 4 potřebuje pouze artefakt junit, protože parametrizovaný běžec je dodáván uvnitř něj. JUnit Verze 5 potřebuje junit-jupiter-params spolu s junit-jupiter-api; bez tohoto artefaktu se @ParameterizedTest a všechny anotace zdrojového kódu nezdaří.

Jupiter poskytuje @CsvFileSource(resources = “/data.csv”, numLinesToSkip = 1), který čte řádky z testovací cesty tříd. JUnit Verze 4 nemá žádný vestavěný ekvivalent, takže metoda @Parameters musí před vrácením kolekce otevřít a analyzovat samotný soubor.

In JUnit 4 to může, ale běžec parametrizuje celou třídu, takže každá metoda se spustí jednou pro každý řádek dat. Jupiter parametrizuje jednotlivé metody, takže i obyčejné metody @Test ve stejné třídě se provedou přesně jednou.

Asistenti umělé inteligence čtou signaturu metody a navrhují hraniční řádky, jako jsou nula, záporné, maximální a přetečné vstupy, které ručně psaná tabulka často přehlíží. Revzobrazit každý vygenerovaný očekávaný výsledek, protože model může vytvořit věrohodný řádek s nesprávnou odpovědí.

GitHub Copilot lešení vytváří rychle, ale často se míchá JUnit 4 a Jupiter importuje a někdy zanechává anotaci zdroje u prosté metody @Test. Před spuštěním sady zkontrolujte importy.

Shrňte tento příspěvek takto: