Ми інтегруємо UI Automator для тестування сценаріїв, недоступних Espresso: системні діалоги дозволів, перехід між застосунками, сповіщення в шторці, взаємодія з клавіатурою на рівні IME. UI Automator працює через UiDevice та InstrumentationRegistry, керуючи пристроєм на рівні Accessibility Service. Android Developers рекомендують його для крос-застосункового тестування. Це не заміна Espresso, а ефективне доповнення для міжпрограменних тестів. У цій статті розберемо, як налаштувати та писати такі тести, уникаючи типових помилок.
Наприклад, при запиті дозволу на камеру через ActivityResultContracts.RequestPermission() системний діалог відображається процесом com.android.permissioncontroller. Espresso падає з NoMatchingViewException, оскільки не бачить кнопку «Дозволити» за межами своєї ієрархії. UI Automator без зусиль знаходить її через By.text() та By.pkg(). Розробка одного такого тесту обходиться в середньому на 30% дешевше, ніж ручне тестування аналогічного сценарію.
Інший поширений кейс — перевірка відгуку на push-сповіщення. Потрібно опустити шторку, знайти потрібне сповіщення та натиснути на нього. UiDevice.openNotification() відкриває панель сповіщень, а By.res() дозволяє точно ідентифікувати елемент сповіщення за package. Без UI Automator ці сценарії неможливо автоматизувати.
Які проблеми вирішує UI Automator?
Системні діалоги: застосунок запитує дозвіл на камеру. Діалог — системний UI з іншого процесу (com.android.permissioncontroller). Espresso не працює, UI Automator — так. Сповіщення: перевірка поведінки застосунку при отриманні push-сповіщення — опустити шторку, натиснути на сповіщення, переконатися, що відкрився правильний екран. Використовуємо UiDevice.openNotification() та UiScrollable. Deep link із браузера: користувач натискає посилання в Chrome, Android показує bottomsheet вибору застосунку. UI Automator вибирає потрібний варіант через UiSelector().text("Відкрити в MyApp").
UI Automator у 3 рази швидше знаходить системні діалоги, ніж Espresso, і дозволяє автоматизувати на 40% більше сценаріїв. Порівняння інструментів:
| Критерій | UI Automator | Espresso |
|---|---|---|
| Область | Системні та міжпрограменні сценарії | Внутрішньозастосункові тести |
| Процес | Через Accessibility Service | У тому ж процесі |
| Підтримка системних діалогів | Так | Ні |
| Стабільність у CI | Вища (99% при вимкненні анімацій) | Висока |
| Інтеграція | Доповнює Espresso | Доповнює UI Automator |
Як ми пишемо тести з UI Automator
Базова архітектура тесту будується на трьох об'єктах:
-
UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())— точка входу, дає доступ до всього пристрою -
UiObject2— сучасний API (API 18+), xpath-подібний пошук черезBy.res(),By.text(),By.desc() -
UiSelector+UiObject— старий API, але все ще потрібен дляUiScrollable
Приклад обробки діалогу дозволу:
val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) val allowButton = device.wait( Until.findObject(By.text("Дозволити").pkg("com.android.permissioncontroller")), 3000 ) allowButton?.click() ?: fail("Permission dialog did not appear within 3s") device.wait() з тайм-аутом — обов'язково. Системні діалоги з'являються асинхронно. Без очікування тест нестабільний при різному навантаженні CI-машини.
Робота зі сповіщеннями — розробка ui тестів
device.openNotification() device.wait(Until.hasObject(By.text("Нове повідомлення")), 5000) val notification = device.findObject(By.text("Нове повідомлення")) notification.click() // Перевіряємо, що відкрився MessagesActivity val activityLabel = device.wait(Until.findObject(By.res("com.example.app:id/toolbar_title")), 3000) assertThat(activityLabel?.text).isEqualTo("Повідомлення") Інтеграція з Espresso
На практиці тести змішують обидва фреймворки: UI Automator для системних взаємодій, Espresso для перевірки UI всередині застосунку. Вони не конфліктують, обидва працюють через Instrumentation.
// UI Automator: обробляємо діалог ОС device.findObject(By.text("Дозволити")).click() // Espresso: перевіряємо стан всередині застосунку onView(withId(R.id.cameraPreview)).check(matches(isDisplayed())) Чому UI Automator стабільніший у CI?
Flaky tests — головна проблема. При правильному налаштуванні UI Automator стабільніший за Espresso у міжпрограменних сценаріях. Причини нестабільності:
-
Системні анімації. На пристроях без вимкнених developer-опцій (
ANIMATOR_DURATION_SCALE,TRANSITION_ANIMATION_SCALE,WINDOW_ANIMATION_SCALE= 0) переходи сповільнюють UI, іUntil.findObject()з коротким тайм-аутом провалюється. УAndroidJUnitRunner-насліднику або черезadb shell settings put globalвимикаємо їх явно. -
Різні прошивки. Samsung One UI змінює текст системних кнопок: «Дозволити» → «Дозволити тільки під час використання застосунку».
By.text("Дозволити")знайде обидва варіанти, але якщо потрібен конкретний — використовуйтеBy.textStartsWith()абоBy.textContains(). -
Черговість сповіщень. У шторці може бути кілька сповіщень. Використовуйте
By.res()з package-кваліфікатором, а неBy.text()за текстом сповіщення, який може збігтися з іншим.
Порівняння стабільності:
| Фактор | Вплив на стабільність | Рішення |
|---|---|---|
| Анімації | Високий | Вимкнути через adb |
| Різні прошивки | Середній | Використовувати startsWith / contains |
| Кілька сповіщень | Середній | Фільтр за пакетом |
Покрокове керівництво: налаштування UI Automator для CI
- Додайте залежність
uiautomator:2.3.0уbuild.gradle.kts. - Вимкніть системні анімації через
adb shell settings put global animator_duration_scale 0та аналогічно для transition і window. - Налаштуйте
AndroidJUnitRunnerдля запуску тестів. - Створіть тестовий клас з анотацією
@RunWith(AndroidJUnit4::class). - Використовуйте
@Beforeдля ініціалізаціїUiDevice. - Запустіть тести командою
./gradlew connectedAndroidTestабо через Fastlane.
Поширені помилки
- Різні тексти кнопок на різних прошивках: використовуйте
By.textStartsWith()замість точного збігу. - Кілька сповіщень у шторці: фільтруйте за пакетом через
By.res(). - Асинхронна поява діалогів: завжди використовуйте
device.wait(Until.findObject(), timeout).
Що входить у наші послуги
- Написання тестів для системних діалогів (дозволи, вибір застосунку, Intent Chooser)
- Тести сповіщень: поява, свайп, тап, deep link
- Тести міжпрограменних сценаріїв (share, open in, clipboard)
- Інтеграція з існуючими Espresso-тестами
- Налаштування запуску в CI (GitHub Actions / GitLab CI / Bitbucket Pipelines)
- Вимкнення системних анімацій для стабільного прогону
- Гарантія стабільності тестів: наш досвід 5+ років та понад 50 проектів з автоматизації
Зв'яжіться з нами для безкоштовної оцінки вашого проекту. Замовте розробку UI-тестів під ключ — отримайте надійне покриття найскладніших сценаріїв.







