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