Зависимые тесты (Test Interdependency)
Тест явно рассчитывает на то, что другой тест уже выполнился и оставил систему в нужном состоянии. Зависимость закреплена через @Order или просто предполагается по алфавитному порядку.
Симптомы
- Использование
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)с@Order - Тест-метод не создаёт свои данные, а использует объекты, созданные в
@BeforeAllпредыдущего теста - «Тест 2 нельзя запустить без теста 1»
- При запуске подмножества тестов —
NullPointerExceptionилиEntityNotFoundException - Комментарии вида
// предполагаем, что createUser уже выполнился
Причины возникновения
- Попытка избежать повторения кода (создания данных) через цепочку тестов
- Перенос стиля интеграционных скриптов (шаг 1 → шаг 2 → шаг 3) в unit/e2e тесты
- Незнание о
@BeforeEachи фабричных методах как альтернативах - Экономия времени прогона: «зачем создавать пользователя дважды?»
Почему это проблема
- Каскадные падения: сломался тест 1 → упали тесты 2, 3, 4, ... — непонятно, где реальный дефект
-
Нельзя запустить в одиночку: CI-конфигурация
run only failed testsне работает - Нельзя параллелизировать: JUnit может запускать тесты в любом порядке в разных потоках
- Ложная зависимость: тест 2 «тестирует» логику теста 1, а не систему
Решение
Каждый тест самодостаточен — создаёт всё необходимое в своём теле или @BeforeEach:
// ❌
@Test @Order(2)
void deleteUser() {
userService.delete("ivan@test.com"); // кто создал этого пользователя?
}
// ✅
@Test
void deleteUser() {
userService.create("ivan@test.com"); // создаём сами
userService.delete("ivan@test.com");
assertFalse(userService.exists("ivan@test.com"));
}