Ночью интеграционный тест проверки срока действия токена иногда падает из-за перехода через полночь. Как сделать такую проверку детерминированной?
Тест должен управлять временем через контролируемый источник времени, а не зависеть от системных часов. В проверке задают фиксированный момент и отдельно проверяют границы срока действия токена: до истечения, точно в момент истечения и после него.
Зависимость от реального времени появилась естественно: приложение обычно напрямую обращается к системным часам. Для обычного сценария это удобно, но интеграционные тесты начинают зависеть от момента запуска, часового пояса, перехода через полночь и различий между средами.
Контролируемый источник времени применяют как способ отделить бизнес-логику от внешнего состояния системы. Это делает результат теста воспроизводимым и позволяет проверять временные границы без ожидания реального наступления нужного момента.
Если тест использует текущую дату, его результат зависит от того, когда именно выполняется операция. Например, токен может считаться действительным в начале теста, но истечь между созданием тестовых данных и проверкой.
Попытка добавить фиксированную задержку лишь маскирует проблему. Такой тест становится медленным и всё равно может быть нестабильным из-за нагрузки, точности часов, сетевых задержек или различий в правилах округления времени.
Приложение должно получать время через отдельную абстракцию, например через компонент «часы». В рабочей среде этот компонент возвращает системное время, а в интеграционном тесте ему задают заранее известный момент.
Тест должен явно определить временную точность контракта. Если срок хранится с точностью до секунды, сравнение не должно случайно учитывать наносекунды; при этом нельзя бездумно округлять время, иначе можно скрыть ошибку на границе срока.
Проверка должна учитывать, чьи часы являются источником истины. Если срок действия токена вычисляет сервер, клиентский тест не должен считать свой локальный момент абсолютно точным: нужно проверять серверное поведение и явно определить допустимый временной запас, если он предусмотрен контрактом.
Обычно проверяют три состояния: токен действителен до границы, истёк после неё и обрабатывается корректно непосредственно на границе. Важно также использовать единый стандарт представления времени, например UTC, чтобы тест не зависел от часового пояса среды.
Не следует изменять системные часы на машине с тестами: это может повлиять на другие процессы, сертификаты, планировщики и параллельные тесты. Подмена источника времени внутри приложения безопаснее, но требует, чтобы все значимые участки кода действительно использовали этот источник, а не обращались к системным часам напрямую.
Сервис выдавал токен на 15 минут. Интеграционный тест создавал токен, ждал несколько секунд и проверял доступ после истечения срока. В CI он периодически падал: задержки и погрешность времени приводили к тому, что запрос иногда выполнялся до, а иногда после границы.
Рассматривались два варианта. Первый — увеличить ожидание: это не устраняло зависимость от реального времени и замедляло прогон. Второй — менять системные часы контейнера: это давало контроль, но создавало риск влияния на другие процессы и параллельные проверки.
Выбрали управляемый источник времени, доступный сервису в тестовом окружении. Тест устанавливал фиксированный момент, создавал токен, затем переводил контролируемое время за границу срока и выполнял запрос. Проверка стала быстрой и воспроизводимой, а отдельный тест подтвердил, что рабочая конфигурация использует реальные системные часы.
Нет, если срок действия вычисляется или проверяется сервером. Подмена локального времени клиента не изменит часы сервера и может создать ложное ощущение контроля. Нужно управлять источником времени там, где принимается проверяемое решение, либо использовать специально предусмотренный тестовый механизм на серверной стороне.
Не всегда. Запас оправдан, если контракт прямо учитывает рассинхронизацию часов или сетевую задержку. Но произвольное увеличение допустимого интервала может скрыть ошибку: токен, который должен быть отклонён, будет считаться действительным. Граница и допустимое расхождение должны быть частью явно проверяемого контракта.
Причина может быть в том, что часть системы использует контролируемые часы, а другая часть напрямую читает системное время. Аналогичная проблема возникает при смешении разных часовых поясов, точности или форматов времени. Поэтому нужно проверить весь путь принятия решения: создание данных, сериализацию, передачу, проверку срока и сохранение результата.