Регрессионное тестирование диагностик MetricKit на фиксированных данных

Регрессионное тестирование диагностик MetricKit на фиксированных данных

Диагностические данные MetricKit поступают не в ритме коммитов. Сегодня в парсере может измениться одна строка, а пропущенное поле обнаружится лишь через несколько дней, когда придёт реальный отчёт о сбое или зависании. Надёжнее обезличить, нормализовать и сохранить уже полученные данные в виде фиксированных фикстур, а затем воспроизводить один и тот же набор входных данных при каждом коммите на облачном Mac. Так проверяется сама цепочка обработки диагностик, а не ожидание следующего случайного события.

Сначала определите границы тестирования

Фиксированные фикстуры подходят для проверки четырёх уровней логики: чтения исходного JSON, сопоставления системных полей с внутренней моделью, удаления конфиденциальных данных и корректной деградации при некорректном вводе. Они не доказывают, что система обязательно сформирует диагностические данные, и не заменяют проверку обратных вызовов на устройстве.

Код приёма данных рекомендуется отделить от бизнес-обработки. Уровень приёма должен только получать jsonRepresentation(), записывать данные в защищённый каталог и ставить их в очередь на отправку. Уровень парсинга принимает Data и возвращает внутреннюю структуру, не зависящую от типов MetricKit. Модульные тесты должны вызывать только этот уровень, чтобы тестовой сборке не приходилось имитировать системные объекты.

Ценность фикстуры не в том, чтобы воспроизвести один успешный разбор, а в том, чтобы зафиксировать контракт входных данных. Тогда после каждого изменения парсера можно точно ответить, какие поля изменились и какая информация была отброшена.

Создайте нормализованные фикстуры для репозитория

Исходные данные могут содержать идентификатор пакета, сведения об устройстве, временные метки, символы стека вызовов и локальные пути. Не добавляйте их в репозиторий напрямую. Сначала сохраните оригинал в среде с ограниченным доступом, затем создайте нормализованную копию, пригодную для репозитория: замените время фиксированным значением, идентификаторы — тестовыми значениями, пути — на $APP и $HOME, а для адресов стека вызовов сохраните формат, но не реальные адреса.

Во внутренний формат можно добавить поле schema, однако исходную версию MetricKit изменять не следует. Организуйте каталог по типам диагностик:

Tests/Fixtures/MetricKit/
├── crash/basic.json
├── crash/missing-stack.json
├── hang/main-thread.json
├── disk-write/threshold.json
└── malformed/truncated.json

Каждая фикстура должна описывать только одно условие. Если один файл одновременно содержит сбой, зависание и аномалию записи на диск, причину неудачного теста будет трудно локализовать. Имя фикстуры должно описывать входные данные, а не ожидаемый результат. Ожидаемые значения лучше хранить в тестовом коде: так при ревью проще заметить, что вместе с фикстурой кто-то попутно изменил и утверждения.

Проверяйте структуру до запуска тестов

Недорогая проверка с помощью jq перед компиляцией тестов позволяет быстро отсеять некорректный JSON, отсутствие версии и ненормализованные пути. Поле diagnostics в примере ниже — это собственный нормализованный массив команды, а не предположение о том, что исходные системные данные имеют такую же структуру.

set -euo pipefail

root="Tests/Fixtures/MetricKit"

find "$root" -name '*.json' -print0 |
while IFS= read -r -d '' file; do
  jq -e '
    type == "object" and
    .schema == 1 and
    (.diagnostics | type == "array") and
    all(.diagnostics[];
      (.kind | type == "string") and
      (.timestamp | type == "string") and
      (.stackID | type == "string")
    )
  ' "$file" >/dev/null

  if grep -E '/Users/|/private/var/|[A-F0-9]{16,}' "$file"; then
    echo "fixture contains unnormalized data: $file" >&2
    exit 1
  fi
done

Структурная проверка не должна требовать наличия всех системных полей, иначе добавление нового необязательного поля будет вызывать бессмысленные сбои. Проверяйте только те ключи, от которых действительно зависит внутренняя обработка, а декодер настраивайте так, чтобы он игнорировал неизвестные поля.

Проверяйте контракт парсера на позитивных и негативных фикстурах

Подготовьте как минимум один набор корректных входных данных и три набора с ошибками. Важно проверить не просто отсутствие исключения, а пригодность результата для агрегации, оповещений и расследования.

Фикстура Ожидаемое поведение Чего не должно происходить
Полные данные о сбое Возвращаются тип, время и идентификатор стека Сохраняется исходный локальный путь
Пустой массив диагностик Возвращается пустой результат Ситуация считается ошибкой декодирования
Отсутствует стек вызовов Результат помечается как неполный Пустой стек выдаётся за корректные данные
Усечённый JSON Возвращается классифицируемая ошибка Процесс немедленно завершается
Неизвестный тип Регистрируется неизвестное значение перечисления Отбрасывается весь пакет данных

Проверяйте внутреннюю модель, а не весь JSON

Снимок всего документа легко нарушить изменением порядка полей или несущественных метаданных. В первую очередь проверяйте количество диагностик, их типы, стабильные идентификаторы и результат обезличивания. Снимок форматированного JSON стоит добавлять только тогда, когда нормализованный вывод используется для обмена между системами. Ошибки также следует представлять сопоставимыми значениями перечисления, например invalidJSON, missingRequiredField и unsupportedDiagnostic, а не сравнивать только изменчивые сообщения на естественном языке.

Интегрируйте проверки в CI на облачном Mac

На облачном Mac от VMRunner запускайте проверку фикстур перед модульными тестами и задавайте фиксированный рабочий каталог для неинтерактивных задач. Возможная последовательность: получить код, выполнить структурную проверку, запустить модульные тесты парсера, сформировать результаты тестирования и в конце убедиться, что в рабочей области не появились незакоммиченные изменения фикстур.

Изменения фикстур необходимо рассматривать отдельно. При появлении нового системного поля сначала определите, должен ли парсер его использовать. Если да, обновите внутреннюю schema и одновременно добавьте тест миграции. Если нет, сохраните мягкий режим декодирования. Не перезаписывайте эталонные файлы автоматически скриптом в CI, иначе реальная потеря полей будет «одобрена» новым ошибочным результатом.

Контрольный список перед слиянием

После введения этих ограничений обработка диагностик MetricKit превращается из подхода «проверим, когда придут данные» в обычное воспроизводимое инженерное тестирование. Формирование системных данных по-прежнему необходимо проверять на устройстве, но парсинг, обезличивание и совместимость больше не зависят от случайного поступления отчётов.

Часто задаваемые вопросы

Могут ли фикстуры MetricKit заменить проверку на устройствах?

Нет. Они проверяют декодирование, обезличивание и преобразование данных, но фактическое создание и доставку диагностик системой необходимо контролировать на устройствах и в рабочей среде.

Стоит ли сохранять исходный JSON MetricKit прямо в Git?

Обычно нет. Обезличенные исходные данные храните в ограниченном хранилище, а в репозиторий добавляйте только нормализованные фикстуры без идентификаторов, локальных путей и конфиденциальных данных.

Должно ли неизвестное новое поле останавливать CI?

Как правило, нет. Дополнительные необязательные поля следует игнорировать, но отсутствие обязательного для внутреннего контракта типа диагностики, времени или идентификатора стека должно завершать тест ошибкой.

выделенный физический узел

Запустите следующую сборку на выделенном облачном Mac

Выберите модель, узел и период оплаты. Конфигурация и сумма в долларах США будут полностью указаны до оформления заказа; актуальный статус доступности отображается в консоли в реальном времени.

Выбрать тариф и заказать