JUnit 5: Szybki poradnik na start
JUnit to świetny framework do testowania jednostkowego w języku programowania Java. Jednakże czwarta wersja tego frameworka ma kilka niedociągnięć, takich jak problem z wieloma narzędziami do uruchamiania testów czy brak testów zależnych, co dla programistów oznacza trudności w tworzeniu testów integracyjnych.
Zespół JUnit 5 opublikował pierwszą ogólnodostępną wersję w dniu 10 września 2017. JUnit pozwala na wiele rodzajów testów i skupia się na Javie 8 i nowszych wersjach. W tym artykule pokażę Ci, jak zacząć pracę z nową wersją JUnit. Wychodzę z założenia, że znasz już JInit 4.12, Javę 8 i Maven.
Przegląd JUnit 5
JUnit 5 składa się z kilku modułów wywodzących się z trzech różnych podprojektów:
- JUnit Platform odpowiada za uruchamianie frameworków testowych na JVM. Określa API silnika testowego, służące do tworzenia frameworku testowego uruchamianego na platformie. Funkcjonuje jako interfejs pomiędzy JUnit i klientami, takimi jak np. narzędzia kompilacji.
- JUnit Jupiter udostępnia silnik testowy do uruchamiania testów opartych na Jupiter na platformie.
- JUnit Vintage pozwala na uruchamianie testów opartych na JUnit 3 i JUnit 4 na platformie JUnit 5.
Instalacja JUnit 5
Aby uruchomić swój pierwszy test z JUnit 5, trzeba dodać następującą zależność do pliku pom.xml:
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.0.2</version>
<scope>test</scope>
</dependency>
Warto zaznaczyć, że w momencie uruchamiania JUnit 5 wymaga wersji Java 8 (lub nowszej).
Zmiany w adnotacjach
JUnit 5 wprowadza istotne zmiany dotyczące adnotacji:
- Adnotacja @Before zmieniła się w @BeforeEach
- Adnotacja @After zmieniła się w @AfterEach
- Adnotacja @BeforeClass zmieniła się w @BeforeAll
- Adnotacja @AfterClass zmieniła się w @AfterAll
- Adnotacja @Ignore zmieniła się w @Disabled
Asercje i instrukcje warunkowe
JUnit 5 dodaje kilka nowych asercji, które świetnie nadają się do używania z lambdami Java 8. Metoda assertAll() może wykonać wszystkie asercje, niezależnie od jej wyników:
@Test
void shouldAddTwoPositiveNumbers() {
assertAll(
() -> assertEquals(4, calculator.add(2, 2)),
() -> assertEquals(6, calculator.add(3, 3))
);
}
Spodziewany parametr został usunięty z adnotacji @Test. Nadal możemy używać mechanizmu @Rule, by sprawdzić, czy przetestowana metoda zwraca wyjątek. Jednak mamy też nowy sposób na testowanie tego. Metoda assertThrows służy do sprawdzenia, czy dany wiersz testu powoduje wystąpienie wyjątku:
@Test
void shouldThrowExceptionWhenDivideByZero() {
Throwable ex = assertThrows(IllegalArgumentException.class,
() -> calculator.divide(2, 0));
assertEquals("Cannot divide by zero", ex.getMessage());
}
Innym parametrem usuniętym z adnotacji @Test jest ograniczenie czasu wykonywania (timeout), które mogło kontrolować czas trwania testu. Lepszym sposobem na mierzenie czasu wykonywania testu są wprowadzone w JUnit 5 asercje assertTimeout iassertTimeoutPreemptively. Pierwsza czeka, aż testowana metoda dobiegnie do końca i zakończy się niepowodzeniem, jeśli wyznaczone ograniczenie czasu wykonywania zostanie przekroczone. Komunikat takiej asercji wskaże, o ile przekroczono dozwolony czas. Asercja assertTimeoutPreemptively zostaje przerwana natychmiast w momencie przekroczenia ograniczenia czasowego.
@Test
void shouldExecuteWithin10ms_waitForCompletion() {
assertTimeout(ofMillis(10),
() -> calculator.add(123, 456));
}
@Test
void shouldExecuteWithin10ms_failIfExceeded() {
assertTimeoutPreemptively(ofMillis(10),
() -> calculator.add(321, 654));
}
W JUnit 5 nie ma metody assertThat(), akceptującej matchery Hamcrest, znane z poprzednich wersji. Zamiast tego, programistów zachęca się do korzystania z wbudowanej obsługi matcherów dostarczanych przez biblioteki asercji innych firm, takie jak AssertJ, Hamcrest, Truth itp.
Instrukcje warunkowe są podobne do asercji z tym wyjątkiem, że muszą one pozostawać prawdziwe – inaczej test zostanie przerwany. Instrukcje warunkowe wykorzystuje się do uruchamiania testów tylko w przypadku, gdy spełnione zostaną określone warunki.
@Test
void runOnWindows7Only() {
assumeTrue("Windows 7".equals(System.getProperty("os.name")));
// Test will be aborted if assumption is not met
// ...
}
Nazwy wyświetlania
Klasy i metody testów mogą deklarować niestandardowe nazwy wyświetlania (zawierające spacje i znaki specjalne), które będą wyświetlane przez narzędzia uruchamiania testów i raporty testowe.
@Test
@DisplayName("2 + 2 addition test")
void testAddition() {
assertEquals(4, calculator.add(2 , 2));
}
Raport testowy wyświetli nazwę testu zamiast nazwy metody, która często bywa zbyt długa i nieczytelna.
Podsumowanie
Opisałem tutaj podstawy obsługi JUnit 5. Jedno z głównych założeń JUnit 5 to ułatwienie wprowadzania udoskonaleń i ewolucji JUnit 5 w przyszłości. Obecna wersja pozwala na tworzenie bardziej czytelnych i intuicyjnych testów. Jest obsługiwana przez Javę 8 i oferuje wiele nowych możliwości testowania. W następnym artykule przyjrzymy się nowym funkcjom JUnit 5, które sprawiają, że ponownie konkuruje z bardziej zaawansowanym TestNG.