Как контролировать регрессию запуска iOS на облачном Mac

Как контролировать регрессию запуска iOS на облачном Mac

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

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

Фраза «открыть приложение» — это ещё не полное определение теста. Как минимум необходимо зафиксировать конфигурацию сборки, модель Simulator, версию среды выполнения, исходные данные приложения и аргументы запуска. Цель теста также должна быть единственной и чёткой: например, измерять только время от создания процесса до появления первого интерактивного экрана, не включая в результат запрос авторизации или загрузку тестовых данных.

Рекомендуется создать отдельный план Performance.xctestplan, включить в нём только тесты производительности запуска и отключить случайный порядок выполнения. Для перехода в стабильное состояние тестовая среда использует аргументы запуска:

final class LaunchPerformanceTests: XCTestCase {
    override func setUp() {
        continueAfterFailure = false
    }

    func testColdLaunch() {
        let app = XCUIApplication()
        app.launchArguments = ["-uiTesting", "-resetLocalState"]

        let options = XCTMeasureOptions()
        options.iterationCount = 8

        measure(
            metrics: [XCTApplicationLaunchMetric(waitUntilResponsive: true)],
            options: options
        ) {
            app.launch()
        }
    }
}

Аргумент -resetLocalState должен обрабатываться тестовой точкой входа приложения и очищать только локальное состояние, которое можно восстановить. Не используйте этот аргумент в рабочем пути выполнения, чтобы пропускать инициализацию, которую действительно нужно измерять. Иначе результат будет отражать лишь «скорость запуска специальной тестовой версии».

Зафиксируйте состояние облачного Mac и Simulator

Для контроля производительности нужен выделенный физический компьютер, а не общая среда, где неизвестные задачи конкурируют за ресурсы CPU и диска. Перед каждым запуском проверяйте текущий путь к Xcode, доступные экземпляры Simulator и свободное место на диске:

set -euo pipefail

xcode-select -p
xcodebuild -version
xcrun simctl list devices available
df -h "$HOME"

Выберите в плане тестирования один установленный Simulator. Не позволяйте скрипту автоматически выбирать «первое доступное устройство»: при изменении образов исторические данные перестанут быть сопоставимыми. Во время выполнения проверки также не следует параллельно запускать архивирование, обновление зависимостей или масштабную индексацию.

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

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

Запускайте единственную блокирующую проверку через xcodebuild

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

set -o pipefail
mkdir -p Artifacts

xcodebuild test \
  -workspace App.xcworkspace \
  -scheme App \
  -testPlan Performance \
  -destination 'platform=iOS Simulator,name=iPhone 16' \
  -only-testing:AppUITests/LaunchPerformanceTests/testColdLaunch \
  -resultBundlePath Artifacts/Launch.xcresult \
  | tee Artifacts/launch-test.log

Параметр set -o pipefail критически важен: без него после сбоя xcodebuild команда tee в конце конвейера всё ещё может привести к успешному завершению задачи. Следует сохранять и Launch.xcresult, и текстовый журнал: первый позволяет просматривать отдельные измерения и вложения теста, а второй помогает быстро находить ошибки на этапе сборки или запуска.

Проверяемый параметр Способ фиксации Действия после изменения
Xcode Записывать xcodebuild -version Сначала создать новую кандидатную базовую линию
Simulator Зафиксировать модель и среду выполнения Не сравнивать напрямую со старой базовой линией
Конфигурация сборки Использовать один и тот же план тестирования Отклонять временную подмену параметров
Тестовые данные Выполнять детерминированный сброс через аргументы запуска Проверить полноту сброса
Число итераций Всегда использовать 8 запусков Не принимать решение по одному результату

Управляйте базовой линией, а не гонитесь за единичным показателем

Создайте в отчёте Xcode базовую линию производительности для выбранного теста и добавьте сформированные общие файлы базовой линии в систему контроля версий. Изменения базовой линии должны проходить ревью так же, как файлы блокировки зависимостей: в описании коммита необходимо указать источник изменения, проверочный коммит и ожидаемое влияние, а не ограничиваться фразой «обновлены данные производительности».

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

Не следует сразу обновлять базовую линию в следующих случаях:

После сбоя сохраните данные и определите ответственный участок запуска

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

Начинайте диагностику с последних изменений, но не ограничивайтесь прикладным кодом. На путь запуска также влияют изменения конфигурации сборки, параметры диагностики при отладке, увеличение объёма ресурсов и тестовые фикстуры. После исправления сохраните оба файла xcresult — для неудачного и успешного запусков — и укажите сравниваемые коммиты в запросе на слияние.

Ценность надёжной блокирующей проверки заключается не в присвоении времени запуска абсолютной оценки, а в постоянной сопоставимости одного и того же сценария. Зафиксируйте среду, версионируйте базовую линию, сохраняйте подтверждающие данные и проверяйте обновления базовой линии через ревью — только тогда производительность запуска превратится из субъективного ощущения в отслеживаемое инженерное ограничение.

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

Сколько раз следует запускать тест производительности?

Для одного коммита нужно не менее 5 запусков, а в проверке перед слиянием разумно использовать 8 и более итераций при неизменных Simulator, конфигурации сборки и фоновых процессах.

Нужно ли повышать порог сразу после сбоя проверки?

Нет. Сначала повторите тест на том же узле и проверьте состояние Simulator и путь запуска. Базовую линию меняют только после подтверждённого и согласованного изменения поведения приложения.

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

Воспроизводите рабочие процессы на облачном Mac, включая и выключая его по мере необходимости

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

Выбрать конфигурацию и оформить заказ