Чувствительность к контексту (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();