Одинаковый seed, разный snapshot: как найти источник нестабильности теста
Разбор границы seeded UUID и всего тестового пакета: порядок, часы, версии, CSV-колонки и точное сравнение промежуточных результатов.
Повторяемый seed фиксирует результат генератора, но не весь тест приложения. Даже при одинаковых UUID могут меняться порядок записей, временные поля, регистр и сериализация. Чтобы исправить нестабильный snapshot, сравнивайте последовательные этапы подготовки, а не меняйте seed после каждого падения.
Этот материал посвящён поиску различия в уже созданном тесте. Начальная настройка воспроизводимого UUID-набора — отдельная задача. Здесь важнее определить, что именно обещает генератор и что находится за его границей.
Зафиксируйте контроль генератора
Для искусственного набора используйте UUID Neraviko с count=2, seed=guide-fixture-v1, uppercase=false. Версия операции — 1. Два вызова возвращают:
07f7f6ad-b06e-4aaa-8e69-15c2c6d1508c
e524b401-0564-4a14-a2c7-5d7c2109b08c
Результат и равенство упорядоченных массивов проверены прямыми локальными вызовами. Эти значения предназначены только синтетическим фикстурам. Метаданные указывают algorithm=hmac_sha256; без seed используется другой режим system_csprng.
Сохраните версию, параметры и ожидаемый массив рядом с тестом. Формат v4 описан в RFC 9562, раздел 5.4, май 2024; проверено 05.10.2026. Точный seeded набор — контракт конкретной реализации, а не универсальное соответствие seed и UUID для всех библиотек.
Найдите первую меняющуюся границу
Сравнивайте четыре артефакта: массив UUID, записи после привязки к сущностям, записи после сортировки и сериализованный snapshot. Если массив одинаков, а документ различается, не нужно искать ошибку в случайности генератора.
Например, в первом запуске UUID с индексом 0 присвоен объекту alpha, во втором — объекту beta. Значения генератора совпали, но связи изменились. Причиной может быть разный порядок исходной коллекции. Сортируйте по согласованному устойчивому полю до назначения индексов; после назначения не меняйте смысл индекса незаметно.
Не считайте count позицией продолжения. Повторные запросы с одним seed начинаются с индекса 0. Два запроса по две строки повторят один набор; они не образуют четыре независимых элемента. Параллельное получение страниц требует отдельного контракта, которого у UUID-операции v1 нет.
Проверенный пример сериализации
Пусть ID уже получен, а запись имеет два строковых поля. Синтетические входы JSON → CSV:
[{"id":"07f7f6ad-b06e-4aaa-8e69-15c2c6d1508c","label":"alpha"}]
и:
[{"label":"alpha","id":"07f7f6ad-b06e-4aaa-8e69-15c2c6d1508c"}]
В JSON → CSV при trailing_newline=false первый результат начинается заголовком id,label, второй — label,id. Полные результаты проверены на операции версии 1. UUID и логические значения одинаковы, но байтовый snapshot различается: CSV использует порядок ключей первого объекта.
Если порядок колонок часть контракта, стройте объект в этом порядке. Если тест проверяет содержание, сравнивайте разобранную структуру по явным правилам и отдельно тестируйте формат. Нельзя просто сортировать весь текст CSV: это может переставить заголовок и многострочные части поля.
Уберите остальные скрытые входы
Текущее время, случайное значение другой библиотеки и внешнее API находятся вне UUID seed. Передавайте тесту фиксированное искусственное время, фиксированный ответ внешнего сервиса и известную исходную коллекцию. Это решение в вашем тестовом окружении; веб-генератор не замораживает часы приложения.
Проверьте также uppercase: регистр меняет snapshot-строки. В CSV на байтовый результат влияют line_ending, trailing_newline, null_value и spreadsheet_safe. Сохраняйте их вместе с набором, если тест сравнивает файл буквально. Значение null и пустая строка могут стать одинаковыми при несогласованной сериализации.
Версия генератора, переводчик форматов и схема фикстуры могут измениться независимо. Обновляйте ожидаемый результат после объяснения конкретного изменения, а не ради зелёного теста. При диагностике одного сбоя достаточно малого искусственного набора из двух записей.
Когда задача решена
Два запуска при одинаковых входах должны совпадать на нужном уровне: значения, порядок или байты. Запишите этот уровень в тесте. Сохраните минимальный reproducer, который падает при возвращении найденной ошибки, и используйте новые случайные наборы отдельными тестами, если они нужны для расширения покрытия.
Операции Neraviko выполняются на сервере; по контракту сырые запросы и результаты не сохраняются и не логируются по умолчанию. Seed не является секретом и не предназначен созданию новых рабочих идентификаторов. Воспроизводимость теста — свойство контролируемой цепочки, не одного поля настроек.