JUnit: что это, ключевые понятия и как работает

Автор: IT Sectr Опубликовано: 2026-04-08 Время чтения: 8 мин

JUnit — это стандартный фреймворк для модульного тестирования в экосистеме Java и Kotlin, который используется в Android-разработке для проверки бизнес-логики на уровне изолированных компонентов. Фреймворк предоставляет набор аннотаций, assertion-методов и Test Runner для автоматического обнаружения и выполнения тестов. По данным JUnit.org, библиотека остаётся самым популярным решением для unit-тестирования в JVM-экосистеме: более 70% Java-проектов используют JUnit в любой из версий.

Главное

  • JUnit — фреймворк для модульного тестирования Java и Kotlin кода с открытым исходным кодом.
  • Аннотации — @Test, @BeforeEach, @BeforeAll управляют жизненным циклом тестового класса.
  • Assertions — assertEquals, assertTrue, assertThrows проверяют ожидаемые результаты выполнения.
  • Parameterized тесты — позволяют запускать один тест с разными наборами входных данных.
  • Test Runner — инфраструктура JUnit автоматически находит и запускает все тесты в проекте.

Что такое 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

Механизм выполнения JUnit основан на паттерне Test Runner, который сканирует classpath, находит методы с аннотацией @Test, создаёт экземпляр тестового класса и запускает методы в определённом порядке. Test Runner управляет жизненным циклом: вызов BeforeAll → BeforeEach → Test → AfterEach → AfterAll.

Жизненный цикл тестового класса

JUnit оборачивает каждый тестовый метод в отдельный экземпляр класса, что гарантирует изоляцию между тестами. Это означает, что поля класса не сохраняют состояние между разными @Test-методами — каждый тест начинается с чистого объекта.

Базовая структура теста

Простейший тест на JUnit выглядит как метод с аннотацией @Test, внутри которого вызывается тестируемый код и проверяется результат через assertion. Если assertion не проходит — тест считается упавшим, и JUnit сообщает об ошибке.

java
@Test
void additionShouldReturnCorrectSum() {
    var calculator = new Calculator();
    var result = calculator.add(2, 3);
    assertEquals(5, result);
}

Test Runner автоматически находит такой метод, запускает его и сообщает результат. Если метод не выбрасывает исключения — тест пройден (green). Если assertion не срабатывает — тест падает (red).

Аннотации JUnit: жизненный цикл теста

Аннотации JUnit определяют, когда и как должен выполняться тестовый код. В JUnit 5 аннотации находятся в пакете org.junit.jupiter.api и покрывают все этапы: подготовку данных, выполнение теста, очистку ресурсов.

АннотацияНазначениеВыполняется
@TestОбозначает тестовый методОдин раз на вызов
@BeforeEachПодготовка перед каждым тестомПеред каждым @Test
@BeforeAllОдноразовая инициализация классаОдин раз перед всеми тестами
@AfterEachОчистка после каждого тестаПосле каждого @Test
@AfterAllОдноразовое завершение классаОдин раз после всех тестов
@DisplayNameЧеловекочитаемое имя тестаДекорация

Пример использования аннотаций

Рассмотрим полный тестовый класс с корректным жизненным циклом. Метод setUp создаёт свежий экземпляр Calculator перед каждым тестом, а tearDown освобождает ресурсы — например, закрывает файловые дескрипторы или соединения с базой данных.

java
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

Assertions — это статические методы, которые сравнивают фактический результат с ожидаемым и выбрасывают исключение при несовпадении. JUnit 5 предлагает класс org.junit.jupiter.api.Assertions с более чем 25 методами для разных сценариев проверки — от простого сравнения значений до проверки таймаутов и групповых assertion.

  • assertEquals(expected, actual) — проверяет равенство через equals().
  • assertTrue(condition) — проверяет, что условие истинно.
  • assertFalse(condition) — проверяет, что условие ложно.
  • assertNotNull(object) — проверяет, что объект не null.
  • assertNull(object) — проверяет, что объект равен null.
  • assertThrows(exception, executable) — проверяет, что код выбрасывает указанное исключение.
  • assertAll(executables) — группирует несколько проверок и выполняет все, не останавливаясь на первой ошибке.

assertThrows для проверки исключений

Отдельного внимания заслуживает метод assertThrows, который позволяет проверить, что код корректно обрабатывает ошибочные ситуации — деление на ноль, передачу null, превышение лимитов.

java
@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

Parameterized тесты позволяют запустить один и тот же тестовый метод с разными наборами аргументов. В JUnit 5 для этого используется аннотация @ParameterizedTest в комбинации с источником данных — @ValueSource, @CsvSource, @MethodSource или @EnumSource.

Этот подход радикально сокращает дублирование кода: вместо десяти одинаковых тестов для разных значений пишется один параметризованный метод. По данным Google Testing Blog, параметризация снижает объём тестового кода на 40–60% без потери покрытия.

Пример с CsvSource

Аннотация @CsvSource передаёт в тест несколько строк с разделителем-запятой. Каждая строка соответствует одному запуску теста. JUnit автоматически преобразует строковые значения в нужные типы: int, long, String и другие.

java
@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 для сложных объектов

Когда входные данные сложнее простых чисел или строк, используется @MethodSource. Он ссылается на статический метод, который возвращает Stream аргументов — например, Stream of Arguments или Stream of User объектов для тестирования DAO-слоя.

Интеграция JUnit с Android-проектами

В Android-разработке JUnit используется в паре с AndroidX Test, который предоставляет расширения для тестирования Activity, Content Provider и других компонентов Android. JUnit отвечает за модульные тесты (unit tests), выполняемые на JVM без эмулятора, а AndroidX Test — за инструментальные тесты на устройстве.

Настройка Gradle

Для подключения JUnit 5 в Android-проект достаточно добавить зависимость org.junit.jupiter:junit-jupiter в build.gradle уровня модуля. Gradle-плагин AGP поддерживает запуск JUnit 5 тестов на JVM через стандартный Test Runner.

kotlin
// 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")
}

Тестирование ViewModel с JUnit

На практике JUnit чаще всего применяется для тестирования ViewModel и репозиториев — слоёв, которые не требуют Android-контекста или эмулятора. Такой тест выполняется за миллисекунды и может быть запущен сотни раз без потери времени.

  • ViewModel — проверка состояний: loading, success, error.
  • Repository — проверка маппинга данных и обработки ошибок.
  • UseCase — проверка бизнес-логики с моками зависимостей.

JUnit 4 vs JUnit 5: ключевые отличия

JUnit 5 (Jupiter) — это не просто новая версия, а полностью переработанная платформа, разделённая на три модуля: JUnit Platform (запуск тестов на JVM), JUnit Jupiter (API для написания тестов) и JUnit Vintage (обратная совместимость с JUnit 4). Такая модульность позволяет подключать разные Test Engine — например, Spek для Kotlin или TestNG.

ХарактеристикаJUnit 4JUnit 5
Пакетorg.junitorg.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 minJava 5Java 8+

Миграция с JUnit 4 на JUnit 5 не требует переписывания всех тестов — достаточно подключить JUnit Vintage Engine, и старые тесты продолжат работать. Новые тесты рекомендуется писать на JUnit 5, чтобы использовать расширения, лямбды в assertions и встроенную поддержку параметризации.

Часто задаваемые вопросы

Чем JUnit отличается от Mockito?

JUnit — это фреймворк для написания и запуска тестов, а Mockito — библиотека для создания mock-объектов. Они используются вместе: JUnit управляет выполнением теста, а Mockito подменяет зависимости тестируемого класса.

Можно ли использовать JUnit 5 в Android-проектах?

Да, JUnit 5 полностью совместим с Android-проектами. Для unit-тестов достаточно добавить зависимость junit-jupiter в build.gradle. Инструментальные тесты по-прежнему работают через AndroidX Test Runner.

Какой минимальный набор аннотаций нужен для теста?

Минимально достаточно одной аннотации @Test перед методом. Для инициализации и очистки рекомендуются @BeforeEach и @AfterEach, но они не обязательны.

Что такое Test Runner в JUnit?

Test Runner — это компонент JUnit, который сканирует classpath, находит методы с аннотацией @Test, создаёт экземпляры тестовых классов и запускает тесты. В JUnit 5 эту роль выполняет JUnit Platform с подключёнными Test Engine.

Как проверить, что метод выбрасывает исключение?

Используйте assertThrows(Class, Executable) — он принимает тип ожидаемого исключения и лямбду с вызовом метода. JUnit проверяет, что исключение действительно было выброшено, и возвращает его для дополнительной проверки.

Итоги

  • JUnit — стандартный фреймворк модульного тестирования для Java и Kotlin, основа экосистемы xUnit.
  • Аннотации @Test, @BeforeEach, @AfterEach управляют жизненным циклом тестового класса.
  • Assertions — assertEquals, assertTrue, assertThrows проверяют корректность результатов.
  • Parameterized тесты с @CsvSource и @MethodSource сокращают дублирование кода.
  • JUnit 5 — модульная архитектура с платформой, Jupiter API и поддержкой расширений.
  • Android-интеграция — JUnit работает на JVM через стандартный Test Runner без эмулятора.
  • Test Runner автоматически обнаруживает и запускает @Test-методы, сообщая о результатах.

Мы разработаем мобильное приложение под ключ

IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

Читайте также