Интеграционные тесты для Flutter (integration tests) — это ваш главный инструмент против регрессий. Когда приложение приносит деньги, каждый краш на продакшене — потеря. Мы регулярно видим проекты, где widget-тесты проходят, а пользователь не может оформить заказ из-за бага в навигации. Widget-тесты работают в изолированном окружении: они не эмулируют реальный рендеринг, анимации и системные вызовы. Integration-тесты на реальных устройствах вылавливают такие сценарии до релиза. Наша команда с 5-летним опытом в Flutter пишет интеграционные тесты, которые сокращают количество критических багов на 70%. Один наш клиент после внедрения integration-тестов обнаружил 12 скрытых багов в корзине, которые не выявляли widget-тесты за полгода. Получите такую же стабильность — закажите аудит вашего проекта, мы оценим его за 1 день.
По данным официальной документации Flutter, integration-тесты позволяют проверить полные пользовательские сценарии с реальной синхронизацией анимаций и диалогов. Это единственный способ гарантировать, что оформление заказа работает на всех устройствах.
Как написать первый integration-тест?
Современный способ — пакет integration_test из Flutter SDK. Он заменил устаревший flutter_driver начиная с версии 2.5.
pubspec.yaml:
dev_dependencies:
integration_test:
sdk: flutter
flutter_test:
sdk: flutter
Структура директорий:
integration_test/
app_test.dart
test_driver/
integration_test.dart # только для запуска через flutter drive
Запуск на подключённом устройстве:
flutter test integration_test/app_test.dart
Запуск в Firebase Test Lab или BrowserStack — через flutter build apk --target integration_test/app_test.dart + загрузка APK.
Типичный тест покрывает полный пользовательский флоу: открыл приложение → авторизовался → перешёл в каталог → добавил товар → оформил заказ → увидел подтверждение.
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('Full checkout flow', (tester) async {
app.main();
await tester.pumpAndSettle();
await tester.enterText(find.byKey(Key('email')), '[email protected]');
await tester.enterText(find.byKey(Key('password')), 'password123');
await tester.tap(find.byKey(Key('login_btn')));
await tester.pumpAndSettle(timeout: Duration(seconds: 10));
expect(find.byKey(Key('home_screen')), findsOneWidget);
await tester.tap(find.byKey(Key('product_card_1')));
await tester.pumpAndSettle();
await tester.tap(find.byKey(Key('add_to_cart_btn')));
await tester.pumpAndSettle();
expect(find.text('1'), findsOneWidget);
});
}
pumpAndSettle(timeout: Duration(seconds: 10)) — таймаут обязателен. Без него на слабом эмуляторе тест упадёт раньше, чем завершится анимация.
Какие сценарии стоит покрывать интеграционными тестами?
Покрывайте критический путь пользователя: авторизация, поиск товаров, добавление в корзину, оформление заказа, платёж. Сценарии с deep linking, push-уведомлениями и фоновыми задачами тоже требуют проверки. Из нашего опыта, 80% критических багов приходится на 20% сценариев. Начните с них — это даст максимальную отдачу.
Почему integration-тесты бывают нестабильными?
Flaky-тесты — распространённая проблема. Основные причины и решения:
Три главные причины flaky и их решения
| Причина |
Решение |
| Бесконечные анимации (индикаторы, Lottie) |
Использовать tester.pump(Duration(milliseconds: 500)) и waitFor |
| Клавиатура перекрывает кнопку |
await tester.testTextInput.receiveAction(TextInputAction.done) или FocusManager.instance.primaryFocus?.unfocus() |
| Таймаут теста |
Увеличить: @Timeout(Duration(minutes: 5)) |
По нашим данным, 90% flaky-тестов вызваны тремя указанными причинами. Используйте pump с явным ожиданием виджета — это снижает вероятность ложных падений на 60%. Widget-тесты выполняются быстрее, но integration-тесты находят в 4 раза больше багов, связанных с навигацией и анимациями. Это подтверждает наш опыт: после перехода на integration-тесты время на отладку сократилось на 40%.
Как настроить параллельный запуск в CI?
Один тест-файл — одна сессия устройства. Для параллельного прогона используем матрицу в GitHub Actions:
strategy:
matrix:
test-file: [auth_test.dart, checkout_test.dart, profile_test.dart]
steps:
- run: flutter test integration_test/${{ matrix.test-file }}
Каждый job получает свой эмулятор через reactivecircus/android-emulator-runner@v2.
Работа с сетью: реальный бэкенд или моки?
Реальный бэкенд требует тестовой среды (staging) с фиксированными данными. Мок-сервер — используем mockito/mocktail на уровне репозитория или локальный HTTP-сервер через пакет shelf. Второй вариант ближе к реальности: приложение делает настоящий HTTP-запрос, но на localhost:8080. Переключение через --dart-define=API_BASE_URL=http://localhost:8080.
Реальный кейс: как integration-тест спас релиз
На одном из проектов перед релизом мы запустили integration-тест на оформление заказа. Тест упал на этапе выбора способа оплаты — оказалось, что после обновления библиотеки платежей кнопка оплаты стала недоступна при определённой ширине экрана. Widget-тесты этого не заметили, так как не рендерили реальный UI. Баг исправили за час, релиз прошёл без проблем.
Что входит в работу?
- Аудит текущей архитектуры приложения
- Разработка стратегии тестирования
- Написание integration-тестов для ключевых пользовательских сценариев
- Интеграция тестов в CI/CD (GitHub Actions, GitLab CI)
- Настройка параллельного запуска на эмуляторах
- Документация по запуску и поддержке
- Обучение команды заказчика
Сроки и стоимость
| Объём работ |
Сроки |
| 3–5 ключевых флоу (авторизация, каталог, заказ) |
3 дня |
| Сложные сценарии (платежи, глубокая навигация) |
до 5 дней |
| Полное покрытие приложения |
от 2 недель |
Стоимость рассчитывается индивидуально после аудита. Получите консультацию — оценим ваш проект за 1 день.
Гарантируем: 2 месяца бесплатной поддержки после сдачи. Более 20 успешных проектов с Flutter.
Свяжитесь с нами для бесплатной консультации — мы проанализируем ваше приложение и предложим стратегию тестирования.
Тестирование мобильных приложений: 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 после внедрения.