JUnit Assertions — обзор методов Assertions в JUnit 5

Краткое определение
Assertions — статические методы, которые проверяют условия в модульных тестах. Если утверждение не выполняется, тест считается проваленным.
Основные варианты использования и примеры
assertEquals
Метод assertEquals проверяет, что ожидаемое значение равно фактическому. В JUnit 5 существует множество перегрузок: с сообщением об ошибке, с поставщиком сообщения (Supplier), с дельтой для сравнения чисел с плавающей точкой и т.д.
Пример класса, который мы будем тестировать:
package com.program;
public class AssertionsMethods {
public static int square(int num) {
return num * num;
}
}JUnit‑тест для метода square (корректированные имена для согласованности):
package com.program;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
class AssertionsMethodsTest {
@Test
void testSquare() {
assertEquals(25, AssertionsMethods.square(5));
assertEquals(36, AssertionsMethods.square(6), "Значения квадрата не совпали.");
assertEquals(49, AssertionsMethods.square(7), () -> "Значения квадрата не совпали.");
}
}Пояснения:
- assertEquals(expected, actual) — самая простая форма.
- assertEquals(expected, actual, message) — выводит message при провале.
- assertEquals(expected, actual, messageSupplier) — вычисляет message лениво через лямбду.
Важно: для чисел с плавающей точкой используйте версию с дельтой: assertEquals(expectedDouble, actualDouble, delta).
assertNull
assertNull проверяет, что объект равен null. В JUnit 5 три основных перегрузки позволяют указывать сообщение или поставщика сообщения.
Пример:
@Test
public void testStringValue() {
String stringValue = null;
assertNull(stringValue);
assertNull(stringValue, "Значение строки не null");
assertNull(stringValue, () -> "Значение строки не null");
}Пояснение: использование поставщика сообщений полезно, когда формирование сообщения дорогостоящие операции — сообщение будет создано только при неудаче.
assertTrue
assertTrue проверяет, что условие истинно. В JUnit 5 есть варианты, принимающие Boolean, BooleanSupplier и варианты с сообщениями.
Пример использования всех вариантов:
@Test
void testEvenNumbers() {
int num1 = 10;
int num2 = 16;
int num3 = 26;
assertTrue(num1 < num2);
assertTrue(num3 > num2, "Условие не истинно.");
assertTrue(num1 < num3, () -> "Условие не истинно.");
assertTrue(() -> num1 % 2 == 0);
assertTrue(() -> num2 % 2 == 0, "Значение не является чётным.");
assertTrue(() -> num3 % 2 == 0, () -> "Значение не является чётным.");
}Короткие определения:
- BooleanSupplier — функциональный интерфейс, возвращающий boolean; позволяет писать ленивые лямбды.
assertFalse
assertFalse — противоположность assertTrue. При тех же формах аргументов проверяет, что условие ложно.
Пример:
@Test
void testNotEvenNumbers() {
int num1 = 11;
int num2 = 17;
int num3 = 27;
assertFalse(num2 < num1);
assertFalse(num2 > num3, "Условие не ложно.");
assertFalse(num3 < num1, () -> "Условие не ложно.");
assertFalse(() -> num1 % 2 == 0);
assertFalse(() -> num2 % 2 == 0, "Значение является чётным.");
assertFalse(() -> num3 % 2 == 0, () -> "Значение является чётным.");
}Когда утверждение может не сработать — распространённые ошибки и контрпримеры
- Неправильное значение expected/actual: перепутаны аргументы, особенно в старых JUnit‑версиях — результат будет «не совпало», хотя код может быть корректным.
- Сравнение объектов без equals(): при сравнении объектов assertEquals использует equals(); если equals() не переопределён — сравнение по ссылке даст неожиданный результат.
- Плавающая точка: сравнение double/float без дельты приведёт к ложным провалам из‑за точности.
- Ленивые сообщения ошибочно используют выражения с побочными эффектами: лямбда‑поставщик вызывается только при провале, но если код в лямбде зависит от состояния, это может ввести в заблуждение.
- Тесты с побочными эффектами (изменяют состояние) нарушают изоляцию — утверждение может зависеть от предыдущих тестов.
Пример проблемного сравнения объектов:
class Point { int x, y; }
Point p1 = new Point();
Point p2 = new Point();
// если equals не переопределён, assertEquals(p1, p2) провалитсяАльтернативы и комплементарные подходы
- Интеграционные тесты: проверяют взаимодействие компонентов, полезны если unit‑тест не покрывает интеграционные сценарии.
- Тестирование контрактов через property‑based тесты (пример: jqwik, QuickTheories) — для генерации случайных входных данных.
- Мокирование (Mockito, MockK): полезно, когда нужно изолировать зависимость и проверять взаимодействия (verify) вместо значений.
- Бенчмаркинг/производительность (JMH): если цель — проверить поведение при нагрузке, утверждения JUnit не годятся.
Замечание: unit‑тесты не заменяют код‑ревью и статический анализ — они дополняют качество кода.
Ментальные модели и эвристики при написании утверждений
- Малые шаги: писать тесты по одной обязанности метода.
- Arrange‑Act‑Assert: разделяйте подготовку, выполнение и проверку.
- Явные ожидания: проверяйте именно то, что важно; избегайте «больших» assertions, которые завязывают тест на многие детали реализации.
- Локализация ошибок: сообщение в assert должно объяснить, почему ожидание важно (не просто “failed”).
Практический cheat‑sheet (быстрые подсказки)
- assertEquals(expected, actual)
- assertEquals(expected, actual, delta) — для float/double
- assertNull(obj)
- assertNotNull(obj)
- assertTrue(condition)
- assertFalse(condition)
- assertThrows(Exception.class, () -> callThatThrows()) — проверка исключений
- assertAll(“group”, () -> assertEquals(a,b), () -> assertTrue(c)) — группировка утверждений
Пример assertThrows:
@Test
void testException() {
assertThrows(IllegalArgumentException.class, () -> {
Integer.parseInt("not a number");
});
}Критерии приёмки (что должен выполнять unit‑тест)
- Изолированность: тест не зависит от внешнего состояния (файлы, БД, сеть) без явного мокирования.
- Повторяемость: тест должен давать одинаковый результат при повторных запусках.
- Скорость: unit‑тесты выполняются быстро.
- Ясность: сообщение об ошибке помогает найти причину провала.
Ролевые чек‑листы
Разработчик:
- Пишет тесты для критических ветвей кода.
- Использует ясные assert‑сообщения.
- Покрывает граничные случаи.
Тестировщик/QA:
- Проверяет сценарии отказов и исключения.
- Прогоняет тесты в CI и фиксит нестабильные тесты.
Технический руководитель:
- Контролирует покрытие и архитектуру тестов.
- Проверяет, чтобы тесты не тестировали реализацию, а контракт.
Мини‑методология: как быстро ввести Assertions в проект
- Выделите критические модули (парсеры, бизнес‑логику, валидаторы).
- Пишите тесты для граничных условий и исключений в первую очередь.
- Настройте CI на запуск unit‑тестов при каждом PR.
- Рефакторите тесты вместе с кодом, следя за скоростью и стабильностью.
Набор тестовых случаев и проверок (примеры для метода square)
- Позитивный кейс: square(5) == 25
- Нулевой кейс: square(0) == 0
- Отрицательное число: square(-3) == 9
- Большие числа: проверка переполнения (если требуется)
Критерии приёмки для метода square:
- Все тесты проходят в локальном окружении и в CI.
- Тесты покрывают нулевой, положительные и отрицательные значения.
Глоссарий в одну строку
- Unit‑тест: автоматизированный тест, проверяющий работу одной единицы кода (функции/метода).
- Assertion: утверждение в тесте, проверяющее условие и сигнализирующее о провале, если условие ложно.
- Supplier/BooleanSupplier: функциональные интерфейсы Java для ленивых сообщений и булевых выражений.
Лучшие практики и советы по безопасности тестов
- Не храните чувствительные данные (пароли, токены) в тестах.
- Избегайте зависимости от внешних сервисов; используйте заглушки/моки.
- Проверяйте, что тесты не изменяют глобальное состояние между запусками.
Короткое резюме
Assertions — центральный инструмент модульного тестирования в JUnit 5. Правильное использование assertEquals, assertNull, assertTrue, assertFalse и других методов помогает быстро локализовать ошибки и поддерживать качество кода. Используйте ленивые поставщики сообщений для дорогих операций, проверяйте сравнение объектов через equals(), а для чисел с плавающей точкой — применяйте дельту. Внедряйте тесты в CI, следуйте правилам из методологии и используйте роли‑чек‑листы для разной ответственности.
Важно: unit‑тесты — часть общей стратегии контроля качества; дополняйте их интеграционными тестами и проверками на уровне систем.
Похожие материалы
Векторы кибератак: типы, защита и план реагирования
Whiteboard в Microsoft Teams — как пользоваться
Редактирование фото на iPhone — руководство
Windows 11 без учётной записи Microsoft
Как установить 7‑Zip на Linux