UI-тесты Android на Espresso: разработка, стабильность, CI

UI-тесты на Android часто падают из-за таймингов и асинхронности, превращая прогон в хаос. Мы разрабатываем стабильные Espresso-тесты с использованием IdlingResource и Robot pattern, настраиваем их под ваш проект и интегрируем в CI. Наша команда реализует решение под ключ — от архитектуры до поддержки, обеспечивая надёжность и масштабируемость.

Разработка и поддержка любых видов мобильных приложений:

Информационные и развлекательные мобильные приложения
Новостные приложения, игры, справочники, онлайн-каталоги, погодные, фитнес и здоровье, туристические, образовательные, социальные сети и мессенджеры, квиз, блоги и подкасты, форумы, агрегаторы
Мобильные приложения электронной коммерции
Интернет-магазины, B2B-приложения, маркетплейсы, онлайн-обменники, кэшбэк-сервисы, биржи, дропшиппинг-платформы, программы лояльности, доставка еды и товаров, платежные системы
Мобильные приложения для управления бизнес-процессами
CRM-системы, ERP-системы, управление проектами, инструменты для команды продаж, учет финансов, управление производством, логистика и доставка, управление персоналом, системы мониторинга данных
Мобильные приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, платформы предоставления электронных услуг, платформы кешбека, видеохостинги, тематические порталы, платформы онлайн-бронирования и записи, платформы онлайн-торговли

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

Услуги, которые мы предлагаем
Показано 1 из 1Все 1734 услуг
UI-тесты Android на Espresso: разработка, стабильность, CI
Средний
~3-5 дней
Часто задаваемые вопросы

Разработка UI-тестов для Android-приложения (Espresso)

Вы написали экран логина на Compose, настроили Hilt, добавили Retrofit. Запускаете тест — он падает. Почему? UI-тесты на Android часто flaky — корень почти всегда в игнорировании IdlingResource. Разработчики вставляют Thread.sleep(2000) и надеются, что пройдёт — это путь к хаосу. Без правильно настроенных IdlingResource стабильность редко превышает 60%. Тест-сьют на 100+ тестов требует 2–3 часа на прогон, половина падает из-за тайминга.

Мы предлагаем разработку UI-тестов на Espresso под ключ. Спроектируем архитектуру с паттерном Robot, настроим IdlingResource для всех асинхронных операций, интегрируем с Firebase Test Lab. За 3–5 дней получаете стабильный набор critical user flows (логин, оплата, основной UX). Один из наших проектов — приложение интернет-банка с 1200 тестами — достиг стабильности 98.5% после настройки IdlingResource.

Google официально рекомендует использовать IdlingResource для синхронизации тестов с фоновыми задачами — это основа стабильного автотестирования.

Основы и критичные нюансы

Базовая структура теста Espresso: onView(matcher).perform(action).check(assertion).

@Test
fun loginWithValidCredentials_navigatesToHome() {
    onView(withId(R.id.emailInput))
        .perform(typeText("[email protected]"), closeSoftKeyboard())
    onView(withId(R.id.passwordInput))
        .perform(typeText("password123"), closeSoftKeyboard())
    onView(withId(R.id.loginButton))
        .perform(click())
    onView(withId(R.id.homeTitle))
        .check(matches(isDisplayed()))
}

Самая частая причина нестабильных тестов — IdlingResource. Если приложение делает асинхронный запрос (Retrofit, Coroutine), Espresso не знает об этом и пытается найти следующий элемент до завершения операции. Решение — зарегистрировать IdlingResource.

// Для OkHttp/Retrofit используйте OkHttpIdlingResource
val idlingResource = OkHttpIdlingResource.create("okhttp", okHttpClient)
IdlingRegistry.getInstance().register(idlingResource)

// Для корутин используйте EspressoIdlingResource
IdlingRegistry.getInstance().register(EspressoIdlingResource.getIdlingResource())

Espresso работает в 2–3 раза быстрее UIAutomator за счёт отсутствия sleep.

Почему тесты на Espresso падают?

Помимо IdlingResource, частая проблема — race conditions при работе с RecyclerView или многопоточностью. Используйте IdlingResource для асинхронных операций и CountingIdlingResource для фоновых задач. Наш опыт: после внедрения IdlingResource стабильность тестов вырастает с 60% до 95%.

Проблема Решение
Асинхронные запросы (Retrofit, Coroutine) OkHttpIdlingResource / EspressoIdlingResource
Загрузка изображений (Glide, Coil) GlideIdlingResource
Анимации (Transition, Lottie) Отключить анимации в тестах
RecyclerView с подгрузкой CountingIdlingResource

Jetpack Compose UI testing

Если проект использует Compose, Espresso-подход заменяется на ComposeTestRule:

@get:Rule
val composeTestRule = createAndroidComposeRule<MainActivity>()

@Test
fun loginScreen_showsErrorOnInvalidEmail() {
    composeTestRule.onNodeWithTag("emailInput")
        .performTextInput("invalid-email")
    composeTestRule.onNodeWithTag("loginButton")
        .performClick()
    composeTestRule.onNodeWithText("Неверный формат email")
        .assertIsDisplayed()
}

testTag в Compose — аналог accessibilityIdentifier в iOS. Обязательно проставляем на все тестируемые элементы через Modifier.testTag("loginButton").

Как ускорить написание тестов?

Используем Robot pattern — аналог Page Object для Compose. Он делает тесты читаемыми как сценарии и упрощает рефакторинг. Сравнение:

Критерий Robot pattern Page Object
Синтаксис Цепочки вызовов (Builder) Методы без возврата объекта
Читаемость Высокая, похожа на шаги тест-кейса Средняя, требуется дополнительная структура
Переиспользование Через композицию роботов Через наследование page-классов
Поддержка Compose Нативная, без лишних обёрток Требуется адаптация

Robot pattern подходит для Compose-проектов лучше. Пример:

class LoginRobot(private val composeTestRule: AndroidComposeTestRule<*, *>) {
    fun enterEmail(email: String) = apply {
        composeTestRule.onNodeWithTag("emailInput").performTextInput(email)
    }

    fun enterPassword(password: String) = apply {
        composeTestRule.onNodeWithTag("passwordInput").performTextInput(password)
    }

    fun clickLogin() = apply {
        composeTestRule.onNodeWithTag("loginButton").performClick()
    }

    fun assertHomeVisible() {
        composeTestRule.onNodeWithTag("homeScreen").assertIsDisplayed()
    }
}

// Тест читается как сценарий
@Test
fun validLogin_showsHome() {
    LoginRobot(composeTestRule)
        .enterEmail("[email protected]")
        .enterPassword("pass123")
        .clickLogin()
        .assertHomeVisible()
}

Hilt и DI в инструментальных тестах

Если проект использует Hilt, тесты требуют HiltAndroidRule. Аннотация @BindValue позволяет подменить реальный репозиторий на фейковый без изменения основного кода — тест не зависит от сети или базы данных.

Как написать стабильный тест на Espresso за 5 шагов

  1. Определите сценарий и выделите асинхронные операции.
  2. Зарегистрируйте IdlingResource для каждой операции.
  3. Используйте Robot pattern для структурирования.
  4. Запустите тест локально, проверьте стабильность.
  5. Интегрируйте с CI и Firebase Test Lab.

CI: Firebase Test Lab

Локальный эмулятор достаточен для разработки, но перед релизом — Firebase Test Lab с реальными устройствами. Пример workflow (GitHub Actions):

- name: Run Espresso tests on Firebase Test Lab
  run: |
    gcloud firebase test android run \
      --type instrumentation \
      --app app/build/outputs/apk/debug/app-debug.apk \
      --test app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk \
      --device model=Pixel8,version=34 \
      --device model=GalaxyS23,version=33

Результаты — Logcat, скриншоты при падении, видео прогона — сохраняются в Google Cloud Storage. Настройка CI входит в объём работ.

Что входит в разработку UI-тестов на Espresso

  • Проектирование архитектуры тестов (выбор паттерна, настройка IdlingResource)
  • Написание critical user flows (логин, оплата, основной UX) с Robot pattern
  • Интеграция с CI/CD (GitHub Actions, Firebase Test Lab)
  • Документация по запуску и поддержке тестов
  • Обучение команды (1–2 часа воркшопа)

Мы разработали UI-тесты для 15+ Android-приложений, средняя стабильность — 97%, максимальный проект — 1200 тестов. Среднее время прогона 100 тестов — 15 минут вместо 2 часов без оптимизации.

Срок: от 3 до 10 дней в зависимости от сложности приложения. Стоимость рассчитывается индивидуально. Если вам нужна помощь с внедрением — свяжитесь с нами, мы проведём аудит и предложим решение. Закажите разработку тестового suite — гарантируем стабильность >95% и месяц сопровождения.

Чек-лист для стабильных UI-тестов
  1. Всегда регистрируйте IdlingResource для всех фоновых потоков.
  2. Не используйте Thread.sleep() — используйте явное ожидание через IdlingResource.
  3. Убедитесь, что анимации отключены в тестовом профиле устройства.
  4. Запускайте тесты на реальных устройствах через Firebase Test Lab.
  5. Очищайте состояние между тестами (clearState в @Before).
  6. Используйте Robot pattern для читаемости и повторного использования.

Наши компетенции:

Последние работы

  • Разработка мобильного приложения для компании FEEDME
    Разработка мобильного приложения для компании FEEDME
    1009
  • Разработка мобильного приложения для компании XOOMER
    Разработка мобильного приложения для компании XOOMER
    902
  • Разработка мобильного приложения для компании RHL
    Разработка мобильного приложения для компании RHL
    1331
  • Разработка мобильного приложения для компании ZIPPY
    Разработка мобильного приложения для компании ZIPPY
    1179
  • Разработка мобильного приложения для компании Affhome
    Разработка мобильного приложения для компании Affhome
    1106
  • Разработка мобильного приложения для компании FLAVORS
    Разработка мобильного приложения для компании FLAVORS
    713