Инженерный журнал BookaMac

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

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

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

Разделите проверку на три уровня

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

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

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

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

Создавайте отдельный симулятор для каждой задачи

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

sudo xcode-select -s /Applications/Xcode.app
xcrun simctl list devicetypes
xcrun simctl list runtimes

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

set -euo pipefail

DEVICE_SET="$PWD/.simulator-location-tests"
DEVICE_TYPE="com.apple.CoreSimulator.SimDeviceType.iPhone-16"
RUNTIME="com.apple.CoreSimulator.SimRuntime.iOS-18-0"

rm -rf "$DEVICE_SET"
UDID="$(xcrun simctl --set "$DEVICE_SET" create GeoTest "$DEVICE_TYPE" "$RUNTIME")"
xcrun simctl --set "$DEVICE_SET" boot "$UDID"
xcrun simctl --set "$DEVICE_SET" bootstatus "$UDID" -b

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

Задавайте фиксированные координаты и разрешения

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

BUNDLE_ID="com.example.LocationDemo"

xcrun simctl --set "$DEVICE_SET" privacy "$UDID" grant location "$BUNDLE_ID"
xcrun simctl --set "$DEVICE_SET" location "$UDID" set 1.290270,103.851959

xcodebuild test \
  -workspace LocationDemo.xcworkspace \
  -scheme LocationDemo \
  -destination "platform=iOS Simulator,id=$UDID" \
  -resultBundlePath "$PWD/TestResults/LocationTests.xcresult"

Для проверки границ недостаточно одной точки. Подготовьте как минимум три группы координат: внутри области, рядом с границей и за пределами области. Тестовые данные должны описывать ожидаемый результат, а не скрывать смысл за названиями вроде case1 и case2.

Сценарий Входные данные Рекомендуемая проверка
Внутри области Расстояние до центра значительно меньше порогового значения Состояние стабильно остаётся «внутри области»
Рядом с границей По одной точке с каждой стороны порогового значения Правила сравнения и округления согласованы
За пределами области Расстояние до центра значительно больше порогового значения Действие для нахождения внутри области не запускается
Разрешение отключено Отозвать разрешение на геолокацию Отображается состояние с подсказкой, позволяющей восстановить доступ

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

Проверяйте последовательность перемещения с помощью GPX

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

<?xml version="1.0" encoding="UTF-8"?>
<gpx version="1.1" creator="location-ci">
  <wpt lat="1.320000" lon="103.820000">
    <name>outside</name>
  </wpt>
  <wpt lat="1.290270" lon="103.851959">
    <name>inside</name>
  </wpt>
</gpx>

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

xcrun simctl --set "$DEVICE_SET" location "$UDID" start "$PWD/Fixtures/enter-region.gpx"
xcodebuild test \
  -workspace LocationDemo.xcworkspace \
  -scheme LocationRouteTests \
  -destination "platform=iOS Simulator,id=$UDID"
xcrun simctl --set "$DEVICE_SET" location "$UDID" stop

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

Очищайте состояние и сохраняйте данные о сбоях

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

cleanup() {
  xcrun simctl --set "$DEVICE_SET" location "$UDID" stop 2>/dev/null || true
  xcrun simctl --set "$DEVICE_SET" location "$UDID" clear 2>/dev/null || true
  xcrun simctl --set "$DEVICE_SET" shutdown "$UDID" 2>/dev/null || true
}
trap cleanup EXIT

При сбое следует архивировать xcresult, журналы приложения, использованный GPX-файл, идентификаторы устройства и среды выполнения, а также состояние разрешений до начала теста. Снимки экрана помогают при диагностике, но не заменяют структурированные проверки. Если одни и те же координаты многократно приводят к сбою, сначала убедитесь, что набор устройств действительно изолирован, Bundle ID указан правильно, а разрешение предоставлено до запуска приложения. Только после этого проверяйте вычисления бизнес-логики.

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

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

Может ли simctl полностью заменить проверку геолокации на реальном устройстве?

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

Почему тест проходит отдельно, но нестабилен в полной CI-последовательности?

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

Как разделить проверки с фиксированной точкой и GPX-маршрутом?

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

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

Перенесите проверенный рабочий процесс в облачный Mac, работающий онлайн 365 дней в году

Выберите BookaMac M4 или BookaMac M4 Pro под свои задачи и при оформлении заказа проверьте регион, срок аренды и дополнительные варианты хранилища.

Выбрать вариант аренды