JUnit — це стандартний фреймворк для модульного тестування в екосистемі Java та Kotlin, який використовується в Android-розробці для перевірки бізнес-логіки на рівні ізольованих компонентів. Фреймворк надає набір анотацій, assertion-методів та Test Runner для автоматичного виявлення та виконання тестів. За даними JUnit.org, бібліотека залишається найпопулярнішим рішенням для unit-тестування в JVM-екосистемі: понад 70% Java-проєктів використовують JUnit у будь-якій з версій.
Головне
JUnit — це фреймворк з відкритим вихідним кодом для написання та запуску повторюваних модульних тестів на мові Java та Kotlin. Він входить в екосистему xUnit — сімейства фреймворків, заснованих на архітектурі Kent Beck та Erich Gamma, і є стандартним інструментом тестування в Android Studio та IntelliJ IDEA.
Основне завдання JUnit — ізолювати невеликий фрагмент коду (метод, клас) і перевірити його поведінку в контрольованих умовах. Тести пишуться у вигляді звичайних Java/Kotlin класів з анотаціями, а фреймворк бере на себе виявлення тестів, управління їхнім життєвим циклом та збір статистики виконання.
Перша версія JUnit з'явилася в 1997 році і кардинально змінила підхід до розробки, популяризувавши практики Test-Driven Development (TDD). Сьогодні JUnit 5 (Jupiter) — актуальна версія, повністю перероблена під модульну архітектуру з підтримкою Java 8+ та розширень.
Механізм виконання JUnit заснований на паттерні Test Runner, який сканує classpath, знаходить методи з анотацією @Test, створює екземпляр тестового класу та запускає методи в певному порядку. Test Runner керує життєвим циклом: виклик BeforeAll → BeforeEach → Test → AfterEach → AfterAll.
JUnit обгортає кожен тестовий метод в окремий екземпляр класу, що гарантує ізоляцію між тестами. Це означає, що поля класу не зберігають стан між різними @Test-методами — кожен тест починається з чистого об'єкта.
Найпростіший тест на JUnit виглядає як метод з анотацією @Test, всередині якого викликається код, що тестується, і перевіряється результат через assertion. Якщо assertion не проходить — тест вважається таким, що впав, і JUnit повідомляє про помилку.
@Test
void additionShouldReturnCorrectSum() {
var calculator = new Calculator();
var result = calculator.add(2, 3);
assertEquals(5, result);
}
Test Runner автоматично знаходить такий метод, запускає його та повідомляє результат. Якщо метод не викидає винятків — тест пройдено (green). Якщо assertion не спрацьовує — тест падає (red).
Анотації JUnit визначають, коли і як має виконуватися тестовий код. У JUnit 5 анотації знаходяться в пакеті org.junit.jupiter.api і покривають всі етапи: підготовку даних, виконання тесту, очищення ресурсів.
| Анотація | Призначення | Виконується |
|---|---|---|
| @Test | Позначає тестовий метод | Один раз на виклик |
| @BeforeEach | Підготовка перед кожним тестом | Перед кожним @Test |
| @BeforeAll | Одноразова ініціалізація класу | Один раз перед усіма тестами |
| @AfterEach | Очищення після кожного тесту | Після кожного @Test |
| @AfterAll | Одноразове завершення класу | Один раз після всіх тестів |
| @DisplayName | Людиночитане ім'я тесту | Декорація |
Розглянемо повний тестовий клас з коректним життєвим циклом. Метод setUp створює свіжий екземпляр Calculator перед кожним тестом, а tearDown звільняє ресурси — наприклад, закриває файлові дескриптори або з'єднання з базою даних.
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();
}
}
Assertions — це статичні методи, які порівнюють фактичний результат з очікуваним та викидають виняток при неспівпадінні. JUnit 5 пропонує клас org.junit.jupiter.api.Assertions з більш ніж 25 методами для різних сценаріїв перевірки — від простого порівняння значень до перевірки таймаутів та групових assertion.
Окремої уваги заслуговує метод assertThrows, який дозволяє перевірити, що код коректно обробляє помилкові ситуації — ділення на нуль, передачу null, перевищення лімітів.
@Test
void divisionByZeroShouldThrowException() {
Calculator calc = new Calculator();
ArithmeticException exception = assertThrows(
ArithmeticException.class,
() -> calc.divide(10, 0)
);
assertEquals("Cannot divide by zero", exception.getMessage());
}
Параметризовані тести дозволяють запустити один і той самий тестовий метод з різними наборами аргументів. У JUnit 5 для цього використовується анотація @ParameterizedTest у комбінації з джерелом даних — @ValueSource, @CsvSource, @MethodSource або @EnumSource.
Цей підхід радикально скорочує дублювання коду: замість десяти однакових тестів для різних значень пишеться один параметризований метод. За даними Google Testing Blog, параметризація знижує обсяг тестового коду на 40–60% без втрати покриття.
Анотація @CsvSource передає в тест кілька рядків з роздільником-комою. Кожен рядок відповідає одному запуску тесту. JUnit автоматично перетворює рядкові значення в потрібні типи: int, long, String та інші.
@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);
}
Коли вхідні дані складніші за прості числа або рядки, використовується @MethodSource. Він посилається на статичний метод, який повертає Stream аргументів — наприклад, Stream of Arguments або Stream of User об'єктів для тестування DAO-шару.
В Android-розробці JUnit використовується в парі з AndroidX Test, який надає розширення для тестування Activity, Content Provider та інших компонентів Android. JUnit відповідає за модульні тести (unit tests), що виконуються на JVM без емулятора, а AndroidX Test — за інструментальні тести на пристрої.
Для підключення JUnit 5 в Android-проєкт достатньо додати залежність org.junit.jupiter:junit-jupiter в build.gradle рівня модуля. Gradle-плагін AGP підтримує запуск JUnit 5 тестів на JVM через стандартний 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")
}
На практиці JUnit найчастіше застосовується для тестування ViewModel та репозиторіїв — шарів, які не потребують Android-контексту або емулятора. Такий тест виконується за мілісекунди і може бути запущений сотні разів без втрати часу.
JUnit 5 (Jupiter) — це не просто нова версія, а повністю перероблена платформа, розділена на три модулі: JUnit Platform (запуск тестів на JVM), JUnit Jupiter (API для написання тестів) та JUnit Vintage (зворотна сумісність з JUnit 4). Така модульність дозволяє підключати різні Test Engine — наприклад, Spek для Kotlin або TestNG.
| Характеристика | JUnit 4 | JUnit 5 |
|---|---|---|
| Пакет | org.junit | org.junit.jupiter |
| Базова анотація | @Test (з junit.framework) | @Test (з org.junit.jupiter.api) |
| Before/After | @Before, @After, @BeforeClass | @BeforeEach, @AfterEach, @BeforeAll |
| Параметризовані | @RunWith(Parameterized.class) | @ParameterizedTest + @ValueSource |
| Розширення | @Rule, @ClassRule | @ExtendWith, більш гнучкий API |
| Java min | Java 5 | Java 8+ |
Міграція з JUnit 4 на JUnit 5 не вимагає переписування всіх тестів — достатньо підключити JUnit Vintage Engine, і старі тести продовжать працювати. Нові тести рекомендується писати на JUnit 5, щоб використовувати розширення, лямбди в assertions та вбудовану підтримку параметризації.
Часті запитання
JUnit — це фреймворк для написання та запуску тестів, а Mockito — бібліотека для створення mock-об'єктів. Вони використовуються разом: JUnit керує виконанням тесту, а Mockito підміняє залежності тестованого класу.
Так, JUnit 5 повністю сумісний з Android-проєктами. Для unit-тестів достатньо додати залежність junit-jupiter в build.gradle. Інструментальні тести, як і раніше, працюють через AndroidX Test Runner.
Мінімально достатньо однієї анотації @Test перед методом. Для ініціалізації та очищення рекомендуються @BeforeEach та @AfterEach, але вони не обов'язкові.
Test Runner — це компонент JUnit, який сканує classpath, знаходить методи з анотацією @Test, створює екземпляри тестових класів та запускає тести. У JUnit 5 цю роль виконує JUnit Platform з підключеними Test Engine.
Використовуйте assertThrows(Class, Executable) — він приймає тип очікуваного винятку та лямбду з викликом методу. JUnit перевіряє, що виняток дійсно було викинуто, і повертає його для додаткової перевірки.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також