Чувствительность к контексту (Context Sensitivity)
Тест зависит от внешнего контекста: текущего времени, часового пояса, локали операционной системы или значений переменных окружения. На разных машинах и в разное время результат отличается.
Симптомы
-
LocalDate.now()илиnew Date()прямо в логике теста или тестируемого кода без параметризации -
assertEquals("1 299,00 ₽", formatter.format(...))— зависимость от системной локали - Тест проходит локально (UTC+3), падает на CI (UTC)
-
System.getenv("FEATURE_FLAG")в тесте — результат зависит от настроек машины - Тест проходит сегодня, но упадёт через 30 дней (проверка истечения срока)
Причины возникновения
- Использование
LocalDate.now()— самый очевидный способ получить текущую дату - Нет абстракции над временем в тестируемом коде
- Незнание о
java.time.Clockкак внедряемой зависимости - Тест писался на машине с определённой локалью и никогда не запускался в другом окружении
Почему это проблема
- Нестабильность на CI: CI-сервер в другом часовом поясе → другие результаты форматирования
- Временно-зависимые падения: тест зелёный в январе, красный в феврале (расчёт дат)
- Невоспроизводимость: «у меня проходит, на CI падает» — трудно отлаживать
- Скрытая хрупкость: тест кажется стабильным, но зависит от конфигурации окружения
Решение
Инжектировать Clock, явно указывать Locale, использовать контролируемые значения вместо системных:
// ❌ зависит от системного времени
Invoice invoice = new Invoice(LocalDate.now().minusDays(31));
assertTrue(invoice.isOverdue());
// ✅ фиксированные часы через Clock
Clock fixed = Clock.fixed(
LocalDate.of(2024, 6, 1).atStartOfDay(ZoneOffset.UTC).toInstant(), ZoneOffset.UTC);
Invoice invoice = new Invoice(LocalDate.of(2024, 4, 30), fixed);
assertThat(invoice.isOverdue()).isTrue();