Слайд. Расширенные аннотации и Test Suites в JUnit 5
JUnit 5 предоставляет аннотации для гибкого управления тестами и создания тестовых наборов (Suites).
Основные расширенные аннотации:
• @RepeatedTest — повторяет тест указанное число раз.
• @ParameterizedTest — запускает один тест с разными входными данными.
• @Tag — группировка тестов по категориям.
• @DisplayName — задаёт читаемое имя теста.
• @TestInstance — управляет жизненным циклом экземпляров класса.
• @TestFactory — позволяет создавать динамические тесты во время выполнения.
Test Suite — объединение нескольких классов тестов для коллективного запуска (аннотация @Suite).
Подробное объяснение
JUnit 5 (платформа Jupiter) даёт разработчику больше контроля над тестами, чем предыдущие версии. Помимо базовых аннотаций (@Test, @BeforeEach, @AfterEach), есть набор расширенных, которые делают тесты гибче и удобнее.
1. @DisplayName
Позволяет задать понятное название тесту, которое появится в отчёте:
@DisplayName("Проверка сложения положительных чисел")
@Test
void shouldAddTwoNumbers() {
Assertions.assertEquals(5, new Calculator().add(2, 3));
}
В отчёте IDE или CI вы увидите строку «Проверка сложения положительных чисел» вместо технического имени метода. Это особенно полезно для документирования тестов.
2. @Tag
Теги позволяют группировать тесты — например, разделить на unit, integration, performance и т. д.:
@Tag("integration")
@Test
void testDatabaseConnection() { ... }
Теперь можно запускать только определённые группы:
mvn test -Dgroups=unit
или с помощью фильтра в IDE. Это удобно при CI/CD — можно, например, быстро прогонять только юнит-тесты при каждом коммите и интеграционные — при nightly build.
3. @RepeatedTest
Используется, когда нужно проверить стабильность или случайное поведение кода:
@RepeatedTest(5)
void shouldBeIdempotent() {
int result = MathUtils.randomInRange(1, 10);
Assertions.assertTrue(result >= 1 && result <= 10);
}
Этот тест выполнится 5 раз. JUnit предоставляет в параметр RepetitionInfo номер итерации, если нужно дифференцировать проверки:
@RepeatedTest(value = 3, name = "Повтор {currentRepetition} из {totalRepetitions}")
void repeatedTestExample(RepetitionInfo info) {
System.out.println("Итерация № " + info.getCurrentRepetition());
}
4. @ParameterizedTest
Позволяет запускать один и тот же тест с разными наборами данных.
Данные могут задаваться через аннотации @ValueSource, @CsvSource, @EnumSource, @MethodSource и другие.
Пример проверки метода isEven:
@ParameterizedTest
@ValueSource(ints = {2, 4, 6, 8})
void shouldReturnTrueForEvenNumbers(int number) {
Assertions.assertTrue(MathUtils.isEven(number));
}
Или с параметрами CSV (для нескольких значений):
@ParameterizedTest
@CsvSource({
"2, true",
"3, false",
"10, true"
})
void testIsEven(int number, boolean expected) {
Assertions.assertEquals(expected, MathUtils.isEven(number));
}
JUnit сам подставляет параметры и формирует отдельные под-тесты.
Это особенно полезно для тестирования функций с множеством входных данных без дублирования кода.
5. @TestInstance(Lifecycle.PER_CLASS)
По умолчанию JUnit создаёт новый экземпляр тестового класса для каждого теста.
Иногда это излишне, например, когда подготовка тяжёлая (подключение к ресурсу).
В таких случаях можно объявить:
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class HeavySetupTest {
@BeforeAll
void init() { System.out.println("Один раз перед всеми тестами"); }
@Test
void first() { ... }
@Test
void second() { ... }
}
Теперь @BeforeAll и @AfterAll можно делать не static, и объект создаётся один раз.
6. @TestFactory
Позволяет динамически создавать тесты во время выполнения программы — например, по данным из файла или API.
@TestFactory
Collection<DynamicTest> dynamicTestsFromData() {
List<String> inputs = List.of("abc", "a", "xyz");
return inputs.stream()
.map(data -> DynamicTest.dynamicTest("Проверка длины для " + data,
() -> Assertions.assertTrue(data.length() >= 1)))
.toList();
}
JUnit сгенерирует отдельный тест для каждого элемента списка.
Это удобно для параметрического тестирования больших наборов данных.
7. Test Suites (наборы тестов)
Когда тестов становится много, их объединяют в suite — набор, который можно запускать как один тест.
В JUnit 5 используется пакет org.junit.platform.suite.api:
@Suite
@SelectClasses({UserServiceTest.class, OrderServiceTest.class})
class ServiceTestSuite { }
Здесь @SelectClasses указывает, какие тестовые классы входят в набор.
Есть и другие аннотации:
@SelectPackages("com.example.tests") — выбрать все тесты в пакете;
@IncludeTags("unit") или @ExcludeTags("integration") — фильтровать по тегам.
Теперь можно запустить один suite и протестировать все сервисы разом — удобно для интеграционного уровня.
8. Практическое использование в проекте
Рекомендуется сочетать:
@ParameterizedTest для функций с разными входными данными;
@RepeatedTest для проверки стабильности алгоритмов;
@Tag для разделения по уровням;
Suites для комплексного прогона при сборке проекта.
Так тестовая архитектура становится прозрачной, а выполнение — гибко настраиваемым (можно запустить только unit, только web, только репозитории и т.д.).
