Введение
В современной разработке программного обеспечения unit-тестирование — не просто рекомендация, а необходимость. Unit-тесты помогают убедиться, что отдельные части вашего кода работают корректно, упрощают рефакторинг и повышают общую надёжность приложения. В этой статье мы подробно рассмотрим, как писать unit-тесты в Java 11 с использованием популярного фреймворка JUnit 5, а также познакомимся с Mockito для мокирования зависимостей.
Что такое Unit-тест?
Unit-тест — это автоматизированный тест, проверяющий корректность работы отдельной «единицы» кода (обычно метода или класса) в изоляции от остальной системы.
Основные характеристики хорошего unit-теста:
- Быстрый: должен выполняться за миллисекунды.
- Изолированный: не зависит от других тестов или внешних систем (база данных, сеть и т.д.).
- Повторяемый: всегда даёт один и тот же результат при одинаковых условиях.
- Автоматизированный: не требует ручного вмешательства.
- Читаемый: название и структура теста должны быть понятны без дополнительных пояснений.
Инструменты для Unit-тестирования в Java
JUnit 5
JUnit — самый популярный фреймворк для unit-тестирования в Java. Версия JUnit 5 (также известная как Jupiter) — это полная переработка по сравнению с JUnit 4 и включает множество современных возможностей.
Mockito
Mockito — библиотека для создания моков (mocks) — объектов, имитирующих поведение реальных зависимостей. Это позволяет тестировать код в изоляции.
Другие полезные инструменты
- AssertJ — библиотека для более выразительных и читаемых утверждений.
- Hamcrest — альтернативная библиотека для утверждений (менее популярна в новых проектах).
- Testcontainers — для интеграционных тестов с реальными контейнерами (например, базами данных).
Настройка проекта (Maven)
Для начала добавим зависимости в pom.xml:
Простой пример: тестируем калькулятор
Допустим, у нас есть простой класс Calculator:
Объяснение аннотаций и методов:
- @Test — помечает метод как тестовый.
- @DisplayName — задаёт человекочитаемое имя теста (отображается в IDE и отчётах).
- assertEquals(expected, actual) — проверяет равенство.
- assertThrows(expectedException, executable) — проверяет, что код выбрасывает указанное исключение.
- Для double используется третий параметр — delta (допустимая погрешность), так как числа с плавающей точкой не всегда точны.
Тестирование с зависимостями: Mockito
Реальные классы часто зависят от других компонентов: репозиториев, сервисов, внешних API. Чтобы протестировать такой класс в изоляции, мы заменяем зависимости на моки.
Пример: UserService
Тест с Mockito
Объяснение Mockito-аннотаций:
- @Mock — создаёт мок-объект интерфейса или класса.
- @InjectMocks — создаёт экземпляр тестируемого класса и автоматически внедряет в него моки.
- @ExtendWith(MockitoExtension.class) — активирует Mockito в JUnit 5.
- when(...).thenReturn(...) — задаёт поведение мока: при вызове метода возвращается указанное значение.
Лучшие практики написания Unit-тестов
1. Используйте соглашение об именовании
Название теста должно описывать:
- Что тестируется
- При каких условиях
- Какой ожидаемый результат
Примеры:
- shouldReturnEmptyListWhenNoUsersFound()
- shouldThrowValidationExceptionWhenEmailIsInvalid()
2. Следуйте структуре AAA (Arrange-Act-Assert)
- Arrange — подготовка данных и зависимостей.
- Act — вызов тестируемого метода.
- Assert — проверка результата.
3. Не тестируйте приватные методы
Тестируйте только публичный API. Если приватный метод критически важен — вынесите его в отдельный класс.
4. Избегайте логики в тестах
Тесты не должны содержать if, for, switch. Это усложняет их понимание и снижает надёжность.
5. Покрывайте граничные случаи
- Пустые коллекции
- Null-значения
- Исключительные ситуации
- Максимальные/минимальные значения
Проверка покрытия кода
Для оценки качества тестов используйте инструменты покрытия, например JaCoCo.
После запуска mvn test отчёт появится в target/site/jacoco/index.html.
Важно: 100% покрытие — не цель. Цель — уверенность в корректности кода.
Заключение
Примеры, рассмотренные в статье, можно найти по адресу:
https://github.com/ShkrylAndrei/blog_yandex/tree/main/src/main/java/info/shkryl/unitTest
https://github.com/ShkrylAndrei/blog_yandex/tree/main/src/test/java/info/shkryl/unitTest