JUnit 5 для Java: полное руководство с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение в JUnit 5

JUnit 5 — это современный фреймворк для модульного тестирования (unit testing) на языке Java. Он является эволюционным развитием популярного JUnit 4 и входит в экосистему Java как стандарт де-факто для написания автоматизированных тестов. JUnit 5 — это не просто обновление, а полностью переработанная архитектура, состоящая из трёх подпроектов: JUnit Platform (запуск тестов), JUnit Jupiter (новая модель программирования и расширений) и JUnit Vintage (обратная совместимость с JUnit 3/4).

Зачем нужен JUnit 5? В современной разработке (особенно в методологиях TDD — Test-Driven Development) тестирование — это не опция, а обязательный этап. JUnit 5 позволяет:

  • Автоматизировать проверку кода: Запускать сотни тестов одной командой.
  • Обеспечить регрессионную надёжность: Убедиться, что новый код не сломал старую функциональность.
  • Улучшить дизайн кода: Тестируемый код часто оказывается более модульным и слабо связанным.
  • Документировать поведение: Тесты служат живой документацией, показывающей, как должен работать класс или метод.
  • Интегрироваться в CI/CD: JUnit 5 легко встраивается в Maven, Gradle, Jenkins, GitHub Actions.

Ключевые нововведения JUnit 5 по сравнению с JUnit 4: аннотации нового поколения (@Test, @ParameterizedTest, @Nested), мощная система расширений (Extensions), поддержка лямбда-выражений и потоковых API, а также встроенная поддержка параметризованных и динамических тестов.

Установка JUnit 5

Поскольку Java — это компилируемый язык, установка производится через менеджеры зависимостей (Maven или Gradle). JUnit 5 не устанавливается через pip или npm. Ниже приведены инструкции для двух самых популярных систем сборки.

Установка через Maven (pom.xml)

Добавьте следующие зависимости в ваш файл pom.xml. Рекомендуется использовать последнюю стабильную версию (на момент написания — 5.11.0, проверьте актуальную на MVNRepository).

<dependencies>
    <!-- Основной модуль JUnit Jupiter (включает API, Engine и параметризацию) -->
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter</artifactId>
        <version>5.11.0</version>
        <scope>test</scope>
    </dependency>
    <!-- (Опционально) Для совместимости с JUnit 4 -->
    <dependency>
        <groupId>org.junit.vintage</groupId>
        <artifactId>junit-vintage-engine</artifactId>
        <version>5.11.0</version>
        <scope>test</scope>
    </dependency>
</dependencies>

Установка через Gradle (build.gradle)

Добавьте в секцию dependencies:

dependencies {
    testImplementation 'org.junit.jupiter:junit-jupiter:5.11.0'
    // (Опционально) Для JUnit 4
    testImplementation 'org.junit.vintage:junit-vintage-engine:5.11.0'
}

test {
    useJUnitPlatform() // Обязательно для включения JUnit 5
}

Установка без системы сборки (Plain Java)

Если вы не используете Maven/Gradle, скачайте JAR-файлы с официального репозитория и добавьте их в classpath вашего проекта. Однако это крайне не рекомендуется для реальных проектов.

Быстрый старт: первый тест на JUnit 5

Создадим простой класс Calculator и напишем для него тест.

1. Класс для тестирования (Calculator.java):

public class Calculator {
    public int add(int a, int b) {
        return a + b;
    }

    public int divide(int a, int b) {
        if (b == 0) {
            throw new IllegalArgumentException("Делить на ноль нельзя");
        }
        return a / b;
    }
}

2. Тестовый класс (CalculatorTest.java):

Тестовый класс должен находиться в той же структуре пакетов, но в директории src/test/java.

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

class CalculatorTest {

    private final Calculator calculator = new Calculator();

    @Test
    void testAddition() {
        int result = calculator.add(2, 3);
        assertEquals(5, result, "2 + 3 должно быть равно 5");
    }

    @Test
    void testDivisionByZero() {
        Exception exception = assertThrows(IllegalArgumentException.class, () -> {
            calculator.divide(10, 0);
        });
        assertEquals("Делить на ноль нельзя", exception.getMessage());
    }
}

3. Запуск:

  • В IntelliJ IDEA: нажмите зелёный треугольник рядом с именем класса или метода.
  • В командной строке (Maven): mvn test
  • В командной строке (Gradle): gradle test

В консоли вы увидите зелёный отчёт: тесты пройдены (PASSED).

Основные методы и аннотации JUnit 5

Рассмотрим 10 ключевых аннотаций и методов, которые покрывают 95% потребностей в тестировании.

1. @Test

Что делает: Помечает метод как тестовый. JUnit Platform находит и запускает все методы с этой аннотацией. В отличие от JUnit 4, метод не обязан быть публичным.

Параметры: Не принимает параметров (кроме необязательного имени отображения).

Пример:

@Test
@DisplayName("Проверка сложения положительных чисел")
void shouldAddPositiveNumbers() {
    assertEquals(4, 2 + 2);
}

2. assertEquals

Что делает: Проверяет, что два значения равны (через метод equals()). Если нет — тест падает с AssertionError.

Параметры:

  • expected (Object) — ожидаемое значение.
  • actual (Object) — фактическое значение.
  • message (String, опционально) — сообщение об ошибке.

Пример:

@Test
void testStringEquality() {
    String actual = "Hello".toUpperCase();
    assertEquals("HELLO", actual, "Строка должна быть в верхнем регистре");
}

3. assertThrows

Что делает: Проверяет, что выполнение переданного лямбда-выражения выбрасывает исключение указанного типа. Возвращает объект исключения для дальнейшей проверки.

Параметры:

  • expectedType (Class<T>) — класс ожидаемого исключения.
  • executable (Executable) — лямбда с кодом, который должен выбросить исключение.

Пример:

@Test
void testThrowsOnNullInput() {
    assertThrows(NullPointerException.class, () -> {
        String str = null;
        str.length();
    });
}

4. assertTrue / assertFalse

Что делает: Проверяет, что булево условие истинно (assertTrue) или ложно (assertFalse).

Параметры:

  • condition (boolean) — проверяемое условие.
  • message (String, опционально) — сообщение об ошибке.

Пример:

@Test
void testIsPositive() {
    int number = 5;
    assertTrue(number > 0, "Число должно быть положительным");
    assertFalse(number < 0);
}

5. assertNull / assertNotNull

Что делает: Проверяет, что объект является null (assertNull) или не null (assertNotNull).

Параметры:

  • actual (Object) — проверяемый объект.
  • message (String, опционально) — сообщение об ошибке.

Пример:

@Test
void testUserCreation() {
    User user = new User("Alice");
    assertNotNull(user.getId(), "ID пользователя не должен быть null после создания");
}

6. assertArrayEquals

Что делает: Проверяет, что два массива равны (одинаковая длина и поэлементное равенство).

Параметры:

  • expected (int[] / Object[] / etc.) — ожидаемый массив.
  • actual (int[] / Object[] / etc.) — фактический массив.

Пример:

@Test
void testArraySort() {
    int[] unsorted = {3, 1, 2};
    Arrays.sort(unsorted);
    assertArrayEquals(new int[]{1, 2, 3}, unsorted);
}

7. @BeforeEach / @AfterEach

Что делает: Метод, помеченный @BeforeEach, выполняется перед каждым тестовым методом. @AfterEach — после каждого. Используется для инициализации и очистки ресурсов (например, создание нового объекта).

Параметры: Нет.

Пример:

private List<String> list;

@BeforeEach
void setUp() {
    list = new ArrayList<>();
}

@AfterEach
void tearDown() {
    list.clear(); // Очистка после каждого теста
}

@Test
void testAddItem() {
    list.add("A");
    assertEquals(1, list.size());
}

@Test
void testEmptyList() {
    assertTrue(list.isEmpty());
}

8. @BeforeAll / @AfterAll

Что делает: Метод выполняется один раз до всех тестов в классе (@BeforeAll) и один раз после всех (@AfterAll). Должен быть статическим (static). Используется для настройки дорогих ресурсов (например, подключение к базе данных).

Параметры: Нет.

Пример:

private static DatabaseConnection connection;

@BeforeAll
static void initAll() {
    connection = new DatabaseConnection("jdbc:h2:mem:test");
    connection.connect();
}

@AfterAll
static void tearDownAll() {
    connection.disconnect();
}

@Test
void testDatabaseQuery() {
    assertTrue(connection.isConnected());
}

9. @ParameterizedTest

Что делает: Позволяет запускать один и тот же тест с разными наборами аргументов. Требует указания источника данных (например, @ValueSource, @CsvSource).

Параметры: Зависит от источника (см. пример).

Пример с @ValueSource:

@ParameterizedTest
@ValueSource(ints = {1, 2, 3, 4, 5})
void testIsPositiveWithMultipleValues(int number) {
    assertTrue(number > 0);
}

Пример с @CsvSource:

@ParameterizedTest
@CsvSource({
    "2, 3, 5",
    "0, 0, 0",
    "-1, 1                    

Рекомендаций