JUnit — to standardowy framework do testów jednostkowych w ekosystemie Java i Kotlin, używany w rozwoju aplikacji Android do sprawdzania logiki biznesowej na poziomie izolowanych komponentów. Framework dostarcza zestaw adnotacji, metod asercji i Test Runnera do automatycznego wykrywania i wykonywania testów. Według danych JUnit.org, biblioteka pozostaje najpopularniejszym rozwiązaniem do testów jednostkowych w ekosystemie JVM: ponad 70% projektów Java używa JUnit w dowolnej wersji.
Najważniejsze
JUnit — to framework z otwartym kodem źródłowym do pisania i uruchamiania powtarzalnych testów jednostkowych w języku Java i Kotlin. Należy do ekosystemu xUnit — rodziny frameworków opartych na architekturze Kenta Becka i Ericha Gammy, i jest standardowym narzędziem testowania w Android Studio i IntelliJ IDEA.
Głównym zadaniem JUnit jest wyizolowanie małego fragmentu kodu (metody, klasy) i sprawdzenie jego zachowania w kontrolowanych warunkach. Testy są pisane jako zwykłe klasy Java/Kotlin z adnotacjami, a framework zajmuje się wykrywaniem testów, zarządzaniem ich cyklem życia i zbieraniem statystyk wykonania.
Pierwsza wersja JUnit pojawiła się w 1997 roku i radykalnie zmieniła podejście do programowania, popularyzując praktyki Test-Driven Development (TDD). Obecnie JUnit 5 (Jupiter) to aktualna wersja, w pełni przeprojektowana pod modułową architekturę z obsługą Java 8+ i rozszerzeń.
Mechanizm wykonania JUnit opiera się na wzorcu Test Runner, który skanuje classpath, znajduje metody z adnotacją @Test, tworzy instancję klasy testowej i uruchamia metody w określonej kolejności. Test Runner zarządza cyklem życia: wywołanie BeforeAll → BeforeEach → Test → AfterEach → AfterAll.
JUnit opakowuje każdą metodę testową w osobną instancję klasy, co gwarantuje izolację między testami. Oznacza to, że pola klasy nie zachowują stanu między różnymi metodami @Test — każdy test zaczyna się od czystego obiektu.
Najprostszy test w JUnit wygląda jako metoda z adnotacją @Test, wewnątrz której wywoływany jest testowany kod i sprawdzany wynik poprzez asercję. Jeśli asercja nie przechodzi — test jest uznawany za nieudany, a JUnit zgłasza błąd.
@Test
void additionShouldReturnCorrectSum() {
var calculator = new Calculator();
var result = calculator.add(2, 3);
assertEquals(5, result);
}
Test Runner automatycznie znajduje taką metodę, uruchamia ją i informuje o wyniku. Jeśli metoda nie rzuca wyjątku — test jest zaliczony (green). Jeśli asercja nie działa — test pada (red).
Adnotacje JUnit określają, kiedy i jak powinien być wykonywany kod testowy. W JUnit 5 adnotacje znajdują się w pakiecie org.junit.jupiter.api i obejmują wszystkie etapy: przygotowanie danych, wykonanie testu, czyszczenie zasobów.
| Adnotacja | Przeznaczenie | Wykonanie |
|---|---|---|
| @Test | Oznacza metodę testową | Raz na wywołanie |
| @BeforeEach | Przygotowanie przed każdym testem | Przed każdym @Test |
| @BeforeAll | Jednorazowa inicjalizacja klasy | Raz przed wszystkimi testami |
| @AfterEach | Czyszczenie po każdym teście | Po każdym @Test |
| @AfterAll | Jednorazowe zakończenie klasy | Raz po wszystkich testach |
| @DisplayName | Czytelna nazwa testu | Dekoracja |
Rozważmy pełną klasę testową z poprawnym cyklem życia. Metoda setUp tworzy świeżą instancję Calculator przed każdym testem, a tearDown zwalnia zasoby — na przykład zamyka deskryptory plików lub połączenia z bazą danych.
class CalculatorTest {
private Calculator calculator;
@BeforeEach
void setUp() {
calculator = new Calculator();
}
@Test
void subtractionShouldReturnCorrectResult() {
int result = calculator.subtract(10, 4);
assertEquals(6, result);
}
@AfterEach
void tearDown() {
calculator.reset();
}
}
Asercje — to statyczne metody, które porównują rzeczywisty wynik z oczekiwanym i rzucają wyjątek w przypadku niezgodności. JUnit 5 oferuje klasę org.junit.jupiter.api.Assertions z ponad 25 metodami dla różnych scenariuszy sprawdzania — od prostego porównania wartości aż do sprawdzania timeoutów i grupowania asercji.
Szczególnej uwagi zasługuje metoda assertThrows, która pozwala sprawdzić, czy kod poprawnie obsługuje sytuacje błędne — dzielenie przez zero, przekazanie null, przekroczenie limitów.
@Test
void divisionByZeroShouldThrowException() {
Calculator calc = new Calculator();
ArithmeticException exception = assertThrows(
ArithmeticException.class,
() -> calc.divide(10, 0)
);
assertEquals("Cannot divide by zero", exception.getMessage());
}
Testy parametryzowane pozwalają uruchomić tę samą metodę testową z różnymi zestawami argumentów. W JUnit 5 służy do tego adnotacja @ParameterizedTest w kombinacji z źródłem danych — @ValueSource, @CsvSource, @MethodSource lub @EnumSource.
To podejście radykalnie zmniejsza powielanie kodu: zamiast dziesięciu identycznych testów dla różnych wartości pisze się jedną metodę parametryzowaną. Według Google Testing Blog, parametryzacja zmniejsza objętość kodu testowego o 40–60% bez utraty pokrycia.
Adnotacja @CsvSource przekazuje do testu kilka wierszy z separatorem przecinkowym. Każdy wiersz odpowiada jednemu uruchomieniu testu. JUnit automatycznie konwertuje wartości łańcuchowe na odpowiednie typy: int, long, String i inne.
@ParameterizedTest
@CsvSource({
"1, 1, 2",
"2, 3, 5",
"10, 20, 30",
"-1, 1, 0"
})
void additionWithMultipleInputs(int a, int b, int expected) {
assertEquals(expected, a + b);
}
Gdy dane wejściowe są bardziej złożone niż proste liczby czy łańcuchy, używa się @MethodSource. Odwołuje się on do statycznej metody, która zwraca Stream argumentów — na przykład Stream of Arguments lub Stream of User obiektów do testowania warstwy DAO.
W rozwoju aplikacji Android JUnit jest używany w parze z AndroidX Test, który dostarcza rozszerzenia do testowania Activity, Content Provider i innych komponentów Androida. JUnit odpowiada za testy jednostkowe (unit tests) wykonywane na JVM bez emulatora, a AndroidX Test za testy instrumentalne na urządzeniu.
Aby podłączyć JUnit 5 w projekcie Android, wystarczy dodać zależność org.junit.jupiter:junit-jupiter w build.gradle poziomu modułu. Wtyczka Gradle AGP obsługuje uruchamianie testów JUnit 5 na JVM przez standardowy Test Runner.
// build.gradle.kts
android {
testOptions {
unitTests.isIncludeAndroidResources = true
}
}
dependencies {
testImplementation("org.junit.jupiter:junit-jupiter:5.11.0")
testImplementation("androidx.test:core-ktx:1.6.1")
}
W praktyce JUnit najczęściej stosuje się do testowania ViewModel i repozytoriów — warstw, które nie wymagają kontekstu Androida ani emulatora. Taki test wykonuje się w milisekundach i może być uruchamiany setki razy bez straty czasu.
JUnit 5 (Jupiter) — to nie tylko nowa wersja, ale w pełni przeprojektowana platforma podzielona na trzy moduły: JUnit Platform (uruchamianie testów na JVM), JUnit Jupiter (API do pisania testów) i JUnit Vintage (wsteczna zgodność z JUnit 4). Taka modułowość pozwala podłączać różne silniki testowe — na przykład Spek dla Kotlin lub TestNG.
| Charakterystyka | JUnit 4 | JUnit 5 |
|---|---|---|
| Pakiet | org.junit | org.junit.jupiter |
| Podstawowa adnotacja | @Test (z junit.framework) | @Test (z org.junit.jupiter.api) |
| Before/After | @Before, @After, @BeforeClass | @BeforeEach, @AfterEach, @BeforeAll |
| Parameterized | @RunWith(Parameterized.class) | @ParameterizedTest + @ValueSource |
| Extension | @Rule, @ClassRule | @ExtendWith, bardziej elastyczne API |
| Java min | Java 5 | Java 8+ |
Migracja z JUnit 4 na JUnit 5 nie wymaga przepisywania wszystkich testów — wystarczy podłączyć JUnit Vintage Engine, a stare testy będą dalej działać. Nowe testy zaleca się pisać w JUnit 5, aby korzystać z rozszerzeń, lambd w asercjach i wbudowanej obsługi parametryzacji.
Często zadawane pytania
JUnit — to framework do pisania i uruchamiania testów, a Mockito — biblioteka do tworzenia obiektów mock. Są używane razem: JUnit zarządza wykonaniem testu, a Mockito podmienia zależności testowanej klasy.
Tak, JUnit 5 jest w pełni zgodny z projektami Android. Do testów jednostkowych wystarczy dodać zależność junit-jupiter w build.gradle. Testy instrumentalne nadal działają przez AndroidX Test Runner.
Minimalnie wystarczy jedna adnotacja @Test przed metodą. Do inicjalizacji i czyszczenia zaleca się @BeforeEach i @AfterEach, ale nie są one obowiązkowe.
Test Runner — to komponent JUnit, który skanuje classpath, znajduje metody z adnotacją @Test, tworzy instancje klas testowych i uruchamia testy. W JUnit 5 tę rolę pełni JUnit Platform z podłączonymi silnikami testowymi.
Użyj assertThrows(Class, Executable) — przyjmuje typ oczekiwanego wyjątku i lambdę z wywołaniem metody. JUnit sprawdza, czy wyjątek rzeczywiście został rzucony, i zwraca go do dodatkowej weryfikacji.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również