JUnit Test sparametryzowany z przykładem przy użyciu @Parameters
⚡ Inteligentne podsumowanie
Testy sparametryzowane w JUnit Uruchamiaj tę samą metodę testową wielokrotnie z różnymi wartościami wejściowymi, aby jedna metoda obejmowała wiele scenariuszy. Adnotacje @RunWith i @Parameters dostarczają zestaw danych dla każdej iteracji.
Czym jest test parametryczny w JUnit?
A test sparametryzowany Test, który wielokrotnie uruchamia tę samą metodę testową, używając różnych wartości. Pomaga programistom zaoszczędzić czas podczas pisania testów, które różnią się jedynie danymi wejściowymi i oczekiwanymi wynikami.
Używając testu sparametryzowanego, można skonfigurować metodę testową, która pobiera dane z pewnego źródła danych. To najprostsza forma testowanie oparte na danych dostępne w środku JUnit samego siebie, bez potrzeby korzystania z żadnej zewnętrznej biblioteki.
Rozważmy prosty test sumujący różne liczby. Kod może wyglądać tak:
Powyższe podejście prowadzi do dużej redundancji. Każda nowa para liczb wymaga kolejnego polecenia assert w tej samej metodzie, a błąd pierwszego polecenia ukrywa każde kolejne polecenie.
Potrzebne jest prostsze podejście. Używając sparametryzowanego testu, możesz dodać jedną metodę, która dostarcza dziesięć danych wejściowych, a test zostanie automatycznie uruchomiony dziesięć razy.
Kroki tworzenia pliku sparametryzowanego JUnit Testowanie
Poniższy kod przedstawia przykład testu sparametryzowanego. Testuje on metodę sum() klasy Airthematic, której pisownia jest użyta w całym przykładowym projekcie.
Krok 1) Utwórz klasę. W tym przykładzie wprowadzimy dwie liczby za pomocą metody sum(int, int), która zwróci sumę podanych liczb.
Krok 2) Utwórz sparametryzowaną klasę testową.
Code Wyjaśnienie
- Code Linia 11: Dodaj adnotację do swojej klasy testowej przy użyciu @RunWith(Parameterized.class).
- Code Linia 13: Deklarowanie zmiennej „firstNumber” jako prywatnej i wpisywanie jako int.
- Code Linia 14: Deklarowanie zmiennej „secondNumber” jako prywatnej i typu int.
- Code Linia 15: Deklarowanie zmiennej „expectedResult” jako prywatnej i typu int.
- Code Linia 16: Deklaracja zmiennej „airthematic” jako prywatnej i typu Airthematic.
@Biegnij z(nazwa_klasy.klasa): @Biegnij z Adnotacja służy do określenia nazwy klasy wykonawczej. Jeśli nie określimy żadnego typu jako parametru, środowisko wykonawcze wybierze BlokowaćJUnit4ClassRunner domyślnie.
Ta klasa odpowiada za uruchamianie testów z nową instancją testu. Odpowiada za wywoływanie JUnit metody cyklu życia, takie jak konfiguracja (zasoby skojarzone) i demontaż (zasoby zwalniające), które są opisane w JUnit urządzenie testowe poradnik.
Aby sparametryzować, należy dodać adnotację @RunWith do klasy i przekazać wymagany plik .class, który ma zostać przetestowany.
Krok 3) Utwórz konstruktor, który przechowuje dane testowe. Przechowuje on 3 zmienne.
Krok 4) Utwórz metodę statyczną, która generuje i zwraca dane testowe.
Code Linia 32,33: Tworzymy tablicę dwuwymiarową (z parametrami wejściowymi do dodawania). Za pomocą metody asList konwertujemy dane na typ List, ponieważ typem zwracanym przez metodę input jest Collection.
Code Linia 30: Korzystanie z @Parametry adnotacja tworząca zestaw danych wejściowych do uruchomienia naszego testu.
Metoda statyczna zidentyfikowana przez adnotację @Parameters zwraca kolekcję, w której każdy wpis będzie danymi wejściowymi dla jednej iteracji testu. Rozważmy element {1,2,3}. Tutaj:
- firstNumber = 1
- drugaLiczba = 2
- oczekiwanyWynik = 3
Tutaj każdy element tablicy będzie przekazywany do konstruktora pojedynczo, ponieważ klasa jest tworzona wielokrotnie. Pięć tablic zadeklarowanych w przykładzie generuje zatem następujące pięć przebiegów:
| Iteracja | pierwszyNumer | drugi numer | oczekiwanyWynik | Linia konsol |
|---|---|---|---|---|
| [0] | 1 | 2 | 3 | Suma Numbers = : 3 |
| [1] | 11 | 22 | 33 | Suma Numbers = : 33 |
| [2] | 111 | 222 | 333 | Suma Numbers = : 333 |
| [3] | 10 | 9 | 19 | Suma Numbers = : 19 |
| [4] | 100 | 9 | 109 | Suma Numbers = : 109 |
Krok 5) Kompletny kod.
Code Wyjaśnienie:
- Code Linia 25: Użycie adnotacji @Before do skonfigurowania zasobów (tutaj Airthematic.class). Adnotacja @Before jest tutaj używana do uruchomienia przed każdym przypadkiem testowym. Zawiera ona warunek wstępny testu.
- Code Linia 36: Utworzenie testu przy użyciu adnotacji @Test.
- Code Linia 39: Tworzenie oświadczenie assert aby sprawdzić czy nasza suma jest równa tej, której się spodziewaliśmy.
Krok 6) Utwórz klasę uruchamiającą testy, aby uruchomić sparametryzowany test:
Code Wyjaśnienie:
- Code Linia 8: Deklarowanie głównej metody klasy Test, która będzie uruchamiać nasze JUnit test.
- Code Linia 9: Wykonywanie przypadków testowych przy użyciu JUnitCore.runClasses, który przyjmuje nazwę klasy testowej jako parametr (w naszym przykładzie używamy AirthematicTest.class).
- Code Linia 11: Przetwarzanie wyniku za pomocą pętli for i drukowanie błędnego wyniku.
- Code Linia 13: Drukowanie pomyślnego wyniku.
Wyjście:
Oto wynik, który pokazuje pomyślny test bez żadnych błędów trace, jak podano poniżej. Należy zauważyć, że JUnit widok wyświetla jeden wpis na wiersz danych zamiast pojedynczego testu:
Zobacz wynik na konsoli, który pokazuje dodanie dwóch liczb:
Testy parametryczne w JUnit 5 z @ParameterizedTest
Powyższy przykład został napisany dla JUnit 4. JUnit 5 (Jupiter) całkowicie usuwa model runnera, więc @RunWith(Parameterized.class), konstruktor danych i pola instancji znikają. JUnit Kod pokazany powyżej nie jest przestarzały: nadal działa bez zmian na JUnit Platforma korzysta z silnika vintage. Nowe testy są jednak zazwyczaj pisane z tagiem @ParameterizedTest.
Wymagane są dwie zależności: junit-jupiter-api dla adnotacji testowych i junit-jowisz-parametry dla wsparcia parametryzowanego. Bez drugiego artefaktu adnotacje źródłowe w ogóle się nie rozwiążą.
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 oferuje kilka źródeł argumentów, a wybór właściwego zależy od kształtu danych:
| Adnotacja źródłowa | Kieszonkowe dzieci | Użyj tego, kiedy |
|---|---|---|
| @ValueSource | Pojedyncza kolumna literałów | Test przyjmuje dokładnie jeden argument |
| @CsvSource | Wiersze w linii rozdzielone przecinkami | Małe tabele liczb i ciągów znaków można łatwo odczytać w pliku |
| @CsvFileSource | Wiersze odczytane z pliku CSV w ścieżce klasy testowej | Zestaw danych jest duży lub jest utrzymywany poza kodem |
| @MethodSource | Statyczna fabryka zwracająca strumień argumentów | Potrzebne są obiekty rzeczywiste, wartości obliczeniowe lub dane losowe |
| @EnumSource | Stałe wyliczenia | Każda wartość wyliczeniowa musi zostać wykonana |
Dwie zasady zaskakują większość początkujących. Adnotacja źródłowa umieszczona w prostej metodzie @Test jest automatycznie ignorowana, więc metoda musi zawierać @ParameterizedTest. Ponadto pusta wartość bez cudzysłowu w @CsvSource jest odczytywana jako null, a pusta wartość w cudzysłowie jest odczytywana jako pusty ciąg znaków.
JUnit Cztery adnotacje użyte w tym artykule mapują się na Jupiter w następujący sposób: @RunWith(Parameterized.class) staje się @ParameterizedTest z adnotacją źródłową, @Parameters staje się @MethodSource lub @CsvSource, a @Before staje się @BeforeEach. Pełna lista znajduje się w JUnit adnotacje poradnik.
Zalety i ograniczenia testów parametryzowanych
Parametryzacja nie jest darmowa. Eliminuje duplikaty, ale również ogranicza sposób pisania testu, dlatego warto poznać obie strony przed konwersją istniejącego pakietu.
Zalety
- Less powielanie: Jedna z metod polega na zastąpieniu bloku niemal identycznych instrukcji assert, jak pokazano na pierwszym zrzucie ekranu w tym artykule.
- Tańsze ubezpieczenie: Dodanie przypadku brzegowego kosztuje jeden dodatkowy wiersz danych zamiast zupełnie nowego walizka testowa Metoda.
- Dokładne raportowanie: Każda iteracja jest raportowana osobno, więc JUnit widok identyfikuje dokładnie wiersz, który uległ awarii, zamiast identyfikować wszystkie agregowane błędy.
- Dane scentralizowane: Dane wejściowe znajdują się w pojedynczej metodzie i mogą być później przeniesione do pliku CSV lub fabryki bez konieczności modyfikowania asercji.
Ograniczenia
- Jedna forma stwierdzenia: Każdy wiersz uruchamia te same asercje, więc scenariusz wymagający innych sprawdzeń nadal wymaga własnej metody testowania.
- Zakres na poziomie klasy w JUnit 4: Obiekt uruchamiający parametryzuje całą klasę, więc niezwiązane z nią metody @Test w tej klasie również są uruchamiane raz na wiersz.
- Nieczytelne raporty: Bez szablonu nazwy błędy pojawiają się jako testAirthematicTest[3], co nie mówi nic o danych, które uległy uszkodzeniu.
- Duże dane wbudowane: Duże tablice wykluczają logikę testową; zamiast tego przenieś je do fabryki @CsvFileSource lub @MethodSource.
Typowe błędy w JUnit Testy sparametryzowane
Większość sparametryzowanych błędów to błędy inicjalizacji zgłaszane przed wykonaniem choćby jednej asercji. Poniższa tabela zawiera listę najczęściej pojawiających się komunikatów i czynników je wywołujących.
| Treść wiadomości | Spowodować | Fix |
|---|---|---|
| Klasa testowa powinna mieć dokładnie jeden konstruktor publiczny | Klasa nie deklaruje konstruktora publicznego lub deklaruje dwa konstruktory publiczne | Zachowaj jeden konstruktor publiczny, którego parametry odpowiadają kolumnom danych |
| Brak publicznej metody parametrów statycznych w klasie | Metoda @Parameters nie jest publiczna statyczna lub zwraca niewłaściwy typ | Zadeklaruj ją jako publiczną statyczną kolekcję i zwróć Arrays.asList(…) |
| IllegalArgumentException: nieprawidłowa liczba argumentów | Wiersz jest szerszy lub węższy niż lista parametrów konstruktora | Ustaw każdą tablicę w kolekcji na taką samą szerokość jak konstruktor |
| Błąd konfiguracji: brak dostawcy argumentów | Test Jupitera zawiera @ParameterizedTest bez adnotacji źródłowej | Dodaj @ValueSource, @CsvSource, @CsvFileSource, @MethodSource lub @EnumSource |
| Wydaje się, że adnotacja źródłowa nic nie robi | Metoda jest oznaczona adnotacją @Test zamiast @ParameterizedTest | Zastąp @Test przez @ParameterizedTest i zaimportuj junit-jupiter-params |
Kolejną pułapką jest współdzielony stan. Ponieważ JUnit Buduje nową instancję dla każdego wiersza, wszystko, co znajduje się w polu statycznym, przetrwa każdą iterację, a wartość zapisana przez wiersz [0] może dyskretnie zmienić wynik wiersza [4]. Zachowaj stan dla każdego wiersza w polach instancji i zresetuj współdzielone zasoby w metodzie @Before lub @BeforeEach. Ogólne wskazówki dotyczące izolowania testów znajdują się w testów jednostkowych poradnik.









