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());
}
Parameterized тесты позволяют запустить один и тот же тестовый метод с разными наборами аргументов. В 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 |
| Parameterized | @RunWith(Parameterized.class) | @ParameterizedTest + @ValueSource |
| Extension | @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 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также