Одинаковый 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 не является секретом и не предназначен созданию новых рабочих идентификаторов. Воспроизводимость теста — свойство контролируемой цепочки, не одного поля настроек.