UI Automator — це фреймворк від Google для автоматизованого UI-тестування Android-додатків, який працює на рівні системи та може взаємодіяти з елементами інтерфейсу за межами одного додатка. На відміну від Espresso, UI Automator не прив'язаний до процесу конкретного додатка: він здатний відкривати системні діалоги, панель сповіщень і перемикатися між додатками. За даними Google Android Developers, UI Automator використовує стандартний Accessibility Service для доступу до UI-дерева пристрою.
Головне
UI Automator — це фреймворк для функціонального UI-тестування Android, який працює на рівні операційної системи. Він надає API для доступу до будь-якого елемента на екрані пристрою, незалежно від того, якому додатку він належить — включаючи системний рядок стану, діалоги дозволів, головний екран і сторонні додатки. Це робить його незамінним для тестування сценаріїв, що виходять за межі одного додатка.
Архітектурно UI Automator використовує Accessibility Service — той самий сервіс, який використовують TalkBack, Switch Access та інші інструменти доступності. Через цей сервіс фреймворк отримує повне дерево UI-компонентів поточного екрана та дозволяє виконувати над ними дії: натискання, свайп, введення тексту, довге натискання.
UI Automator вперше з'явився в Android 4.3 (API 18) і з того часу є частиною Android Testing Support Library як офіційний інструмент Google для кросаплікаційного тестування. В AndroidX Test він доступний як окремий артефакт androidx.test.uiautomator:uiautomator версії 2.3.0 (2024), який підтримує всі версії Android від API 18.
Принцип роботи: UI Automator заснований на скануванні Accessibility-дерева поточного екрана. При виклику методу findObject(selector) фреймворк обходить ієрархію View, знаходить перший елемент, що відповідає умовам UiSelector, і повертає об'єкт UiObject — проксі для взаємодії з реальним View.
Типовий тест UI Automator починається з отримання екземпляра UiDevice, який представляє фізичний пристрій. UiDevice надає методи для пошуку елементів, керування натисканнями кнопок (Home, Back, Recent), повороту екрана та знімків екрана. Після пошуку елемента через UiSelector виконуються дії над UiObject.
У прикладі нижче тест відкриває додаток Settings, знаходить пункт «Батарея» через текст і натискає його. UI Automator не потребує запуску Activity — він працює з будь-яким екраном пристрою, включаючи сторонні додатки.
val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
// Відкрити екран налаштувань
device.pressHome()
device.wait(Until.hasObject(UiSelector().text("Налаштування")), 2000)
// Знайти пункт "Батарея" і натиснути
val batteryItem = device.findObject(
UiSelector().text("Батарея")
)
batteryItem.clickAndWait(Until.newWindow(), 3000)
UiDevice — головний клас для взаємодії з пристроєм. Він надає методи для пошуку елементів, симуляції натискань апаратних кнопок (Home, Back, Menu, Volume), керування живленням, знімків екрана та очікування певних станів екрана. UiDevice створюється один раз на тест і використовується для всіх операцій.
UiSelector — це fluent API для пошуку UI-елементів. На відміну від Espresso ViewMatchers, UiSelector не потребує компіляції — умови пошуку формуються через ланцюжок методів: text(), className(), description(), resourceId(), index(). Кілька умов комбінуються автоматично через логічне AND.
| Метод UiSelector | Призначення |
|---|---|
| text(String) | Пошук за точним текстом елемента |
| textContains(String) | Пошук за частиною тексту |
| resourceId(String) | Пошук за ID ресурсу (напр., com.example:id/button) |
| className(String) | Пошук за іменем класу View |
| description(String) | Пошук за content-description |
| childSelector(selector) | Пошук дочірнього елемента в контейнері |
Коли на екрані кілька елементів з однаковим текстом, UiSelector дозволяє комбінувати критерії: знайти контейнер за ID, потім всередині нього — елемент за текстом і класом. Це гарантує унікальну ідентифікацію потрібного компонента. Метод childSelector звужує область пошуку до вказаного контейнера, що прискорює навігацію по UI-дереву.
val scrollView = device.findObject(
UiSelector().resourceId("android:id/list")
)
// Всередині списку знайти елемент із текстом "Wi-Fi"
val wifiItem = scrollView.findObject(
UiSelector().text("Wi-Fi")
wifiItem.click()
Кросаплікаційне (міжпрограмне) тестування — головна функція, заради якої вибирають UI Automator. Фреймворк може перемикатися між додатками, тестувати OAuth-вхід через браузер, перевіряти системні діалоги (дозволи, вибір додатка) і взаємодіяти з системним рядком стану, панеллю сповіщень і екраном блокування.
Типовий сценарій кросаплікаційного тесту: додаток відкриває браузер для OAuth-авторизації, користувач вводить логін і пароль, браузер перенаправляє назад у додаток. UI Automator перемикається між процесами, знаходить поля введення в браузері, заповнює їх і натискає «Увійти».
// Очікування появи браузера
device.wait(Until.hasObject(
UiSelector().packageName("com.android.chrome")
), 5000)
// Пошук поля введення email у браузері
val emailField = device.findObject(
UiSelector().className("android.widget.EditText").instance(0)
)
emailField.text = "user@example.com"
UI Automator може перевіряти та закривати системні діалоги — дозволи на геолокацію, сповіщення, доступ до файлів. Це критично важливо для тестування першого запуску додатка, коли система послідовно запитує кілька дозволів. Без UI Automator такі сценарії неможливо автоматизувати, оскільки системні діалоги не належать процесу додатка.
Вибір між UI Automator і Espresso залежить від сценарію тестування. Espresso оптимізований для тестування одного додатка з автоматичною синхронізацією та мінімальним boilerplate. UI Automator підходить для сценаріїв, де потрібно взаємодіяти з системою, браузером або кількома додатками.
| Критерій | UI Automator | Espresso |
|---|---|---|
| Область | Весь пристрій, кілька додатків | Один додаток |
| Синхронізація | Ручна (wait, sleep) | Автоматична (Idling Resource) |
| Швидкість | Повільніше (доступ через сервіс) | Швидше (працює всередині процесу) |
| System UI | Підтримує (Notifications, Quick Settings) | Не підтримує |
| Точність пошуку | UiSelector за атрибутами | ViewMatchers за типом та ієрархією |
| Стабільність | Нижча (залежить від таймінгів) | Вища (автоматичне очікування) |
На практиці ці фреймворки часто використовуються разом: Espresso покриває UI-тести основного додатка з високою стабільністю, а UI Automator підключається для сценаріїв, що виходять за межі додатка — OAuth-вхід, системні дозволи, робота з Share Intent. Така комбінація дає максимальне покриття UI при мінімальних витратах на підтримку тестів.
Підключення UI Automator виконується через додавання залежності в build.gradle. Фреймворк входить в AndroidX Test і не потребує додаткових дозволів у маніфесті — доступ до Accessibility Service налаштовується автоматично при запуску інструментального тесту.
Мінімальна конфігурація включає артефакт uiautomator і стандартний тестовий раннер AndroidJUnitRunner. Тести UI Automator розміщуються в директорії src/androidTest і запускаються на емуляторі або фізичному пристрої з Android API 18+.
dependencies {
androidTestImplementation("androidx.test.uiautomator:uiautomator:2.3.0")
androidTestImplementation("androidx.test.ext:junit:1.2.1")
androidTestImplementation("androidx.test:runner:1.6.1")
}
Для отримання екземпляра UiDevice використовується InstrumentationRegistry.getInstrumentation(). UiDevice слід створювати один раз у методі setUp() і використовувати у всіх тестах класу для економії ресурсів пристрою. Важливо враховувати, що UiDevice не є потокобезпечним — всі операції повинні виконуватися в одному потоці тестового методу. Створення нового UiDevice в кожному тесті призводить до накладних витрат і уповільнення виконання. Рекомендується створювати UiDevice один раз у методі beforeClass і використовувати для всіх тестів тестового класу.
На відміну від Espresso, UI Automator не має автоматичної синхронізації. Для очікування появи елементів використовується метод UiDevice.wait(condition, timeout) з об'єктом Until: Until.findObject(selector), Until.hasObject(selector), Until.gone(selector). Без коректних очікувань тести стають flaky через race condition — елемент може не встигнути з'явитися на екрані на момент пошуку. Рекомендується встановлювати таймаут не менше 3–5 секунд для стабільності.
Часті запитання
UI Automator працює на рівні Accessibility Service і може взаємодіяти з будь-якими додатками. Espresso працює всередині процесу одного додатка і використовує автоматичну синхронізацію з UI-потоком. UI Automator краще для міжпрограмних сценаріїв, Espresso — для стабільних тестів одного додатка.
Так, UI Automator працює на всіх пристроях з Android API 18+. Він не потребує root-доступу — використовується стандартний Accessibility Service, який активується через Instrumentation при запуску тестів.
UI Automator використовує Accessibility Service для отримання повного дерева UI-компонентів поточного екрана. Потім UiSelector обходить це дерево і знаходить елементи за заданими критеріями: текст, клас, ID, content-description або їх комбінація.
Так, метод UiDevice.takeScreenshot(storePath) дозволяє зробити знімок поточного екрана та зберегти його у файл. Це корисно для налагодження: при падінні тесту можна зберегти знімок і проаналізувати стан екрана.
UI Automator не має автоматичної синхронізації, тому тести чутливі до таймінгів. Якщо анімація не завершилася або View не встиг відмалюватися, findObject може не знайти елемент. Рішення — використовувати UiDevice.wait() з достатнім таймаутом.
Підсумки
Набір інструментів UI Automator охоплює всі ключові сценарії кросаплікаційного тестування і є стандартом для Android-автоматизації на рівні системи.
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також