Разработка E2E-тестов для мобильного приложения (Maestro)
Мы используем Maestro, потому что это самый быстрый способ покрыть приложение E2E-тестами без танцев с сервером. За 5 лет мы автоматизировали более 50 мобильных проектов — от банковских приложений до маркетплейсов. Недавно для финтех-стартапа с 30 экранами написали 15 YAML-флоу за 4 дня. Регресс сократился с двух дней до четырёх часов, заказчик экономит около 400 000 руб. в год на обслуживании тестов. Maestro — black-box инструмент, он общается с устройством через Accessibility API и не требует модификации кода. Это идеально для регресса ключевых пользовательских путей: регистрация, каталог, оформление заказа. Средний проект сокращает время регрессии на 70%, а стоимость поддержки тестов — на 40% по сравнению с Appium. Гарантируем: каждый тест проходит ревью и запускается на реальных устройствах.
Как Maestro упрощает жизнь мобильному разработчику?
Главное — нулевая конфигурация. Установил через curl, написал YAML, запустил maestro test. Не нужно поднимать Appium-сервер, встраивать агент или разбираться с XCUITest. Maestro сам находит элементы по тексту, accessibilityLabel или id. Для типовых приложений это покрывает 80–90% сценариев.
Как написать тест на Maestro: пошаговая инструкция
- Создайте YAML-файл в папке
flows/.
- Укажите
appId вашего приложения (bundle ID для iOS, package name для Android).
- Напишите последовательность действий:
launchApp, tapOn, inputText, assertVisible.
- Используйте переменные и
runFlow для переиспользования (см. пример ниже).
- Запустите тест командой
maestro test flows/.
YAML-сценарии: просто, но есть нюансы
Минимальный флоу авторизации:
appId: com.example.myapp
---
- launchApp:
clearState: true
- tapOn: "Email"
- inputText: "[email protected]"
- tapOn: "Пароль"
- inputText: "password123"
- tapOn: "Войти"
- assertVisible: "Главная"
tapOn ищет элемент по тексту, accessibilityLabel, testID или id. Если на экране два элемента с одинаковым текстом — Maestro нажмёт на первый. В таких случаях используем tapOn с уточнением: index или id.
- tapOn:
text: "Добавить"
index: 1
- tapOn:
id: "add_to_cart_button"
id на Android — resource-id, на iOS — accessibilityIdentifier. Maestro определяет платформу автоматически.
Переменные и подфлоу
Без переменных и runFlow большие тест-сьюты превращаются в копипасту. Создаём переиспользуемые блоки:
# flows/login.yaml
appId: com.example.myapp
---
- tapOn: "Email"
- inputText: ${EMAIL}
- tapOn: "Пароль"
- inputText: ${PASSWORD}
- tapOn: "Войти"
# flows/checkout_test.yaml
appId: com.example.myapp
env:
EMAIL: [email protected]
PASSWORD: password123
---
- runFlow: flows/login.yaml
- tapOn: "Каталог"
- tapOn: "Купить"
- assertVisible: "Оформление заказа"
Переменные переопределяются при запуске: maestro test --env [email protected].
Запуск: локально и в CI
Локальный запуск — главное преимущество Maestro. Установка и запуск:
curl -Ls "https://get.maestro.mobile.dev" | bash
maestro test flows/
maestro studio
maestro studio — браузерный UI для интерактивного выбора элементов.
Maestro Cloud
Для CI без собственных устройств используем Maestro Cloud. В GitHub Actions:
- name: Run Maestro tests on Maestro Cloud
uses: mobile-dev-inc/action-maestro-cloud@v1
with:
api-key: ${{ secrets.MAESTRO_CLOUD_API_KEY }}
app-file: app/build/outputs/apk/debug/app-debug.apk
flows-file: flows/
Для собственного CI — локальный эмулятор + maestro test.
Почему Maestro, а не Appium или Detox?
Мы часто слышим этот вопрос. Сравним в таблицах:
| Критерий |
Maestro |
Appium |
Detox |
| Конфигурация |
Нет |
Нужен сервер |
Встраивание агента |
| Язык тестов |
YAML |
Java/Python/JS |
JS |
| Облачные устройства |
Maestro Cloud |
AWS Device Farm |
Firebase |
| Кастомные жесты |
Нет |
Да |
Да |
| Доступ к JS |
Нет |
Нет |
Да |
Для стандартных CRUD-приложений Maestro выигрывает по скорости написания и поддержки.
| Сценарий |
Срок (дни) |
Сложность |
| 5–7 флоу (регистрация, каталог, заказ) |
3 |
Низкая |
| Сложные многоэкранные сценарии |
5 |
Средняя |
| Полный регресс (20+ флоу) |
10 |
Высокая |
Ограничения, которые надо знать
Maestro не умеет в кастомные жесты: pinch, rotate, multi-touch. Для приложений с картами или галереей, где нужен зум — Appium или Detox. Нет прямого доступа к JavaScript-контексту (в отличие от Detox). Assertions ограничены видимостью (assertVisible, assertNotVisible). Проверить точное значение атрибута или координату элемента — нельзя.
Несмотря на это, для стандартных CRUD-приложений, маркетплейсов, сервисных приложений Maestro покрывает 80–90% нужных E2E-сценариев с минимальными затратами на поддержку.
Типичные ошибки новичков
- Использование текста, который меняется (дата, время). Лучше использовать testID.
- Забыли очистить состояние между тестами — используйте
clearState: true.
- Неправильный appId — проверьте bundle ID или package name.
- Зависимость от порядка экранов — используйте
runFlow с авторизацией.
Что входит в работу под ключ
- Написание YAML-флоу для ключевых пользовательских сценариев
- Настройка переменных и переиспользуемых подфлоу
- Интеграция с CI (GitHub Actions / GitLab CI)
- Настройка запуска через Maestro Cloud или локальный эмулятор
- Документация по добавлению новых тестов
Сроки и стоимость
3–5 дней в зависимости от количества сценариев. 5–7 флоу для типичного CRUD-приложения — 3 дня. Сложные многоэкранные сценарии с переменными и вложенными флоу — 5 дней. Стоимость рассчитывается индивидуально. Оценим ваш проект за 1 день. Мы гарантируем качество: каждый тест проходит ревью и запускается на реальных устройствах.
Закажите разработку E2E-тестов — напишите нам, мы ответим в течение 2 часов. Получите консультацию по автоматизации регресса для вашего проекта.
Тестирование мобильных приложений: XCTest, Espresso, Detox и Appium
Flaky-тест, падающий на CI раз в пять запусков без воспроизводимой причины, хуже его отсутствия. Команда перестаёт доверять инфраструктуре и отключает тесты — регрессии проскакивают в продакшн. Мы это видим каждый день и знаем, как выстроить надёжную систему тестирования, которая не требует постоянного внимания. Получите консультацию — оценим ваш проект и предложим архитектуру тестов под ваш стек.
Почему flaky-тесты опасны?
Одна нестабильная проверка может завалить пайплайн, заблокировав релиз. Разработчики тратят 15-20% рабочего времени на перезапуск и анализ ложнонегативных сбоев. Автоматизация без стабильности — не экономия, а потеря эффективности. Мы решаем эту проблему на уровне архитектуры: Gray Box-фреймворки (Detox, Patrol) синхронизируются с состоянием приложения, а native инструменты (XCUITest, Espresso) получают правильные IdlingResource и accessibilityIdentifier. Результат: стабильность >99% на CI.
Unit-тесты: что тестировать, а что нет
На iOS XCTest — основа. Бизнес-логика в ViewModel, Interactor, UseCase — тестируется без проблем, если она не тянет UIKit. Типичная ошибка: логика в UIViewController напрямую — тогда unit-тест требует создания view-иерархии, что медленно и нестабильно. Выход — выносить логику в сервисы с @testable import.
Для асинхронного кода в Swift: XCTestExpectation для старого стиля, await + XCTest async для современного. С Combine — XCTestExpectation + sink, но удобнее использовать библиотеки типа CombineExpectations. На Android JUnit 4/5 + Mockito для unit-тестов, Coroutines Test для suspend-функций. runTest {} из kotlinx-coroutines-test — стандарт для ViewModel с StateFlow. Покрытие кода unit-тестами на уровне 80% сокращает время регрессии на 60% (данные наших проектов).
UI-тесты: стабильность важнее покрытия
XCUITest (iOS) и Espresso (Android) — нативные UI-тесты. Работают быстро, интегрированы с IDE, но тестируют одну платформу. Главная проблема XCUITest — хрупкость селекторов. app.buttons["Войти"] падает при смене локализации или рефакторинге accessibility label. Правильный подход: accessibilityIdentifier для тестируемых элементов, никогда не текстовые метки. Идентификаторы из shared enum — чтобы они не расходились между приложением и тестами. Опыт показывает: такая практика снижает flakiness на 90%.
Espresso на Android стабильнее из-за IdlingResource механизма — тест автоматически ждёт завершения background операций. Но кастомные async операции (OkHttp, кастомные Executors) нужно регистрировать в IdlingRegistry вручную, иначе тест не синхронизируется с сетевыми запросами. Мы гарантируем правильную настройку IdlingResource на этапе аудита.
Detox и Patrol: end-to-end для React Native и Flutter
Detox — E2E фреймворк для React Native, разработанный Wix. Работает на реальных устройствах и симуляторах через Gray Box подход: знает о состоянии JS thread и синхронизируется с ним. Это решает главный flakiness-источник — тест не нажимает кнопку, пока приложение занято. Настройка Detox нетривиальна. Требует специальный debug-билд с DetoxInstrumentsServer, конфигурации в package.json и отдельного Appium-сервера не нужно. Типичная проблема: тест стабилен на симуляторе, падает на реальном устройстве из-за анимаций. Решение — animations: disabled в Detox конфигурации для E2E билда.
Patrol — аналог для Flutter. Расширяет встроенный integration_test пакет и добавляет возможность взаимодействовать с нативными системными диалогами (permission prompts, notifications) — то, что flutter_driver и базовый integration_test не умеют. Для CI используется через patrol test --target integration_test/app_test.dart.
Appium: кроссплатформа с ценой
Appium — когда нужно покрыть iOS и Android одними тестами. Использует WebDriver протокол, поверх XCUITest и UiAutomator2 драйверов. Скорость ниже нативных фреймворков, но для команд без ресурсов на две тестовые кодовые базы — компромисс. Appium 2.x с плагинной архитектурой заметно удобнее первой версии. appium-doctor диагностирует окружение — полезен при настройке CI.
CI и параллелизация
Для параллельного запуска XCUITest используем Xcode Cloud или xcodebuild test-without-building с несколькими симуляторами через parallel-testing-enabled. Время прогона 200 UI-тестов с параллелизацией на 4 симулятора — с 40 минут до 12. На Android аналогично используем Firebase Test Lab с шардингом.
| Фреймворк |
Платформа |
Gray Box |
Скорость |
Системные диалоги |
| XCUITest |
iOS |
Нет |
Высокая |
Да (через addUIInterruptionMonitor) |
| Espresso |
Android |
Да (IdlingResource) |
Высокая |
Ограничено |
| Detox |
React Native |
Да |
Средняя |
Ограничено |
| Patrol |
Flutter |
Частично |
Средняя |
Да |
| Appium |
iOS + Android |
Нет |
Низкая |
Да |
Типичные ошибки при настройке (и как их избежать)
| Ошибка |
Последствие |
Решение |
| Использование текстовых меток в селекторах |
Тесты падают при локализации |
accessibilityIdentifier из enum |
| Отсутствие IdlingResource для кастомных Executor |
Espresso не ждёт ответа сервера |
Регистрация в IdlingRegistry |
| Включённые анимации на реальном устройстве в Detox |
Flaky тесты из-за таймингов |
animations: disabled в E2E билде |
| Параллелизация без изоляции состояния |
Гонки данных между тестами |
Запуск каждого теста в свежем симуляторе |
Как мы это делаем: процесс работы
-
Аудит текущего кода и CI — оцениваем flakiness, покрытие, узкие места.
-
Проектирование тестовой архитектуры — выбираем фреймворк, селекторы, моки.
-
Настройка инфраструктуры — CI пайплайн, parallel execution, отчёты (Allure, Xcode Report).
-
Написание тестов — unit, UI, E2E, performance (XCTMetrics, Macrobenchmark).
-
Интеграция и стабилизация — прогон 200+ тестов, отлов flaky-кейсов.
-
Передача документации — архитектура, запуск, troubleshooting.
Что входит в работу (deliverables)
- Архитектурная документация тестового покрытия
- Настроенный CI-пайплайн с параллелизацией и отчётами
- Код тестов (unit, UI, E2E) с styleguide
- Обучение команды (2 часа воркшопа)
- Доступ к тестовым билдам и CI-логам
- Поддержка в течение месяца после сдачи (фикс flakiness, обновление под новые версии)
Сроки ориентировочно
Настройка инфраструктуры с нуля (CI, unit + UI тесты, отчёты) — 2-3 недели. Написание покрытия для существующего приложения — от 2 недель до месяца в зависимости от объёма. Оценим ваш проект за 2 дня — свяжитесь с нами. 5+ лет опыта в автоматизации, 50+ успешных проектов, сертифицированные специалисты по iOS/Android. Гарантируем стабильность тестов >98% на CI после внедрения.