Framework pengujian UI Automator menyediakan serangkaian API untuk membuat pengujian UI yang berinteraksi dengan aplikasi pengguna dan aplikasi sistem.
Pengantar pengujian UI Automator modern
UI Automator 2.4 memperkenalkan Domain Specific Language (DSL) yang disederhanakan dan kompatibel dengan Kotlin yang menyederhanakan penulisan pengujian UI untuk Android. Platform API baru ini berfokus pada penemuan elemen berbasis predikat dan kontrol eksplisit atas status aplikasi. Gunakan untuk membuat pengujian otomatis yang lebih mudah dikelola dan andal.
UI Automator memungkinkan Anda menguji aplikasi dari luar proses aplikasi. Hal ini memungkinkan Anda menguji versi rilis dengan penerapan minifikasi. UI Automator juga membantu saat menulis pengujian macrobenchmark.
Fitur utama pendekatan modern meliputi:
- Cakupan pengujian
uiAutomatorkhusus untuk kode pengujian yang lebih bersih dan ekspresif. - Metode seperti
onElement,onElements, danonElementOrNulluntuk menemukan elemen UI dengan predikat yang jelas. - Mekanisme tunggu bawaan untuk elemen bersyarat
onElement*(timeoutMs: Long = 10000) - Pengelolaan status aplikasi eksplisit seperti
waitForStabledanwaitForAppToBeVisible. - Interaksi langsung dengan node jendela aksesibilitas untuk skenario pengujian multi-aplikasi.
- Kemampuan screenshot bawaan dan
ResultsReporteruntuk pengujian dan proses debug visual.
Menyiapkan project
Untuk mulai menggunakan UI Automator API modern, perbarui file project Anda
build.gradle.kts untuk menyertakan dependensi terbaru:
Kotlin
dependencies {
...
androidTestImplementation("androidx.test.uiautomator:uiautomator:2.4.0-alpha05")
}
Groovy
dependencies {
...
androidTestImplementation "androidx.test.uiautomator:uiautomator:2.4.0-alpha05"
}
Konsep API inti
Bagian berikut menjelaskan konsep inti UI Automator API modern.
Cakupan pengujian uiAutomator
Akses semua UI Automator API baru dalam blok uiAutomator { ... }. Fungsi ini membuat UiAutomatorTestScope yang menyediakan lingkungan ringkas dan aman untuk operasi pengujian Anda.
uiAutomator {
// All your UI Automator actions go here
startApp("com.example.targetapp")
onElement { textAsString() == "Hello, World!" }.click()
}
Menemukan elemen UI
Gunakan UI Automator API dengan predikat untuk menemukan elemen UI. Predikat ini memungkinkan Anda menentukan kondisi untuk properti seperti teks, status yang dipilih atau difokuskan, dan deskripsi konten.
onElement { predicate }: Menampilkan elemen UI pertama yang cocok dengan predikat dalam waktu tunggu default. Fungsi ini akan menampilkan pengecualian jika tidak menemukan elemen yang cocok.// Find a button with the text "Submit" and click it onElement { textAsString() == "Submit" }.click() // Find a UI element by its resource ID onElement { viewIdResourceName == "my_button_id" }.click() // Allow a permission request watchFor(PermissionDialog) { clickAllow() }onElementOrNull { predicate }: Mirip denganonElement, tetapi menampilkannulljika fungsi tidak menemukan elemen yang cocok dalam waktu tunggu. Perintah ini tidak memberikan pengecualian. Gunakan metode ini untuk elemen opsional.val optionalButton = onElementOrNull { textAsString() == "Skip" } optionalButton?.click() // Click only if the button existsonElements { predicate }: Menunggu hingga setidaknya satu elemen UI cocok dengan predikat yang diberikan, lalu menampilkan daftar semua elemen UI yang cocok.// Get all items in a list Ui element val listItems = onElements { className == "android.widget.TextView" && isClickable } listItems.forEach { it.click() }
Berikut beberapa tips untuk menggunakan panggilan onElement:
Rantai panggilan
onElementuntuk elemen bertingkat: Anda dapat merantai panggilanonElementuntuk menemukan elemen dalam elemen lain, mengikuti hierarki induk-turunan.// Find a parent Ui element with ID "first", then its child with ID "second", // then its grandchild with ID "third", and click it. onElement { viewIdResourceName == "first" } .onElement { viewIdResourceName == "second" } .onElement { viewIdResourceName == "third" } .click()Tentukan waktu tunggu untuk fungsi
onElement*dengan meneruskan nilai yang mewakili milidetik.// Find a Ui element with a zero timeout (instant check) onElement(0) { viewIdResourceName == "something" }.click() // Find a Ui element with a custom timeout of 10 seconds onElement(10_000) { textAsString() == "Long loading text" }.click()
Berinteraksi dengan elemen UI
Berinteraksi dengan elemen UI dengan menyimulasikan klik atau menetapkan teks di kolom yang dapat diedit.
// Click a Ui element
onElement { textAsString() == "Tap Me" }.click()
// Set text in an editable field
onElement { className == "android.widget.EditText" }.setText("My input text")
// Perform a long click
onElement { contentDescription == "Context Menu" }.longClick()
Menangani status dan pemantau aplikasi
Kelola siklus proses aplikasi Anda dan tangani elemen UI yang tidak terduga yang mungkin muncul selama pengujian.
Pengelolaan siklus proses aplikasi
API menyediakan cara untuk mengontrol status aplikasi yang sedang diuji:
// Start a specific app by package name. Used for benchmarking and other
// self-instrumenting tests.
startApp("com.example.targetapp")
// Start a specific activity within the target app
startActivity(SomeActivity::class.java)
// Start an intent
startIntent(myIntent)
// Clear the app's data (resets it to a fresh state)
clearAppData("com.example.targetapp")
Menangani UI yang tidak terduga
watchFor API memungkinkan Anda menentukan pengendali untuk elemen UI yang tidak terduga, seperti dialog izin, yang mungkin muncul selama alur pengujian. Hal ini menggunakan mekanisme pemantau internal, tetapi menawarkan lebih banyak fleksibilitas.
import androidx.test.uiautomator.PermissionDialog
@Test
fun myTestWithPermissionHandling() = uiAutomator {
startActivity(MainActivity::class.java)
// Register a watcher to click "Allow" if a permission dialog appears
watchFor(PermissionDialog) { clickAllow() }
// Your test steps that might trigger a permission dialog
onElement { textAsString() == "Request Permissions" }.click()
// Example: You can register a different watcher later if needed
clearAppData("com.example.targetapp")
// Now deny permissions
startApp("com.example.targetapp")
watchFor(PermissionDialog) { clickDeny() }
onElement { textAsString() == "Request Permissions" }.click()
}
PermissionDialog adalah contoh ScopedWatcher<T>, dengan T adalah
objek yang diteruskan sebagai cakupan ke blok di watchFor. Anda dapat membuat pemantau kustom berdasarkan pola ini.
Menunggu visibilitas dan stabilitas aplikasi
Terkadang, pengujian perlu menunggu elemen menjadi terlihat atau stabil. UI Automator menawarkan beberapa API untuk membantu hal ini.
The waitForAppToBeVisible("com.example.targetapp") menunggu elemen UI dengan
nama paket yang diberikan muncul di layar dalam waktu tunggu yang dapat disesuaikan.
// Wait for the app to be visible after launching it
startApp("com.example.targetapp")
waitForAppToBeVisible("com.example.targetapp")
Gunakan waitForStable() API untuk memverifikasi bahwa UI aplikasi dianggap stabil sebelum berinteraksi dengannya.
// Wait for the entire active window to become stable
activeWindow().waitForStable()
// Wait for a specific Ui element to become stable (e.g., after a loading animation)
onElement { viewIdResourceName == "my_loading_indicator" }.waitForStable()
Menggunakan UI Automator untuk Macrobenchmark dan Profil Dasar Pengukuran
Gunakan UI Automator untuk pengujian performa dengan Jetpack Macrobenchmark dan untuk membuat Profil Dasar Pengukuran, karena UI Automator menyediakan cara yang andal untuk berinteraksi dengan aplikasi Anda dan mengukur performa dari perspektif pengguna akhir.
Macrobenchmark menggunakan UI Automator API untuk mendorong UI dan mengukur interaksi.
Misalnya, dalam benchmark startup, Anda dapat menggunakan onElement untuk mendeteksi kapan UI
konten dimuat sepenuhnya, sehingga Anda dapat mengukur Waktu hingga Tampilan Penuh
(TTFD). Dalam benchmark jank, UI Automator API digunakan untuk men-scroll daftar atau menjalankan animasi untuk mengukur waktu frame. Fungsi seperti startActivity() atau startIntent() berguna untuk membuat aplikasi berada dalam status yang benar sebelum pengukuran dimulai.
Saat membuat Profil Dasar Pengukuran, Anda mengotomatiskan perjalanan penting pengguna (CUJ) aplikasi untuk mencatat class dan metode mana yang memerlukan pra-kompilasi. UI Automator adalah alat yang ideal untuk menulis skrip otomatisasi ini. Penemuan elemen berbasis predikat DSL modern dan mekanisme tunggu bawaan (onElement) menghasilkan eksekusi pengujian yang lebih kuat dan deterministik dibandingkan dengan metode lainnya.
Stabilitas ini mengurangi ketidakstabilan dan memastikan bahwa Profil Dasar Pengukuran yang dihasilkan secara akurat mencerminkan jalur kode yang dieksekusi selama alur pengguna terpenting Anda.
Fitur lanjutan
Fitur berikut berguna untuk skenario pengujian yang lebih kompleks.
Berinteraksi dengan beberapa jendela
UI Automator API memungkinkan Anda berinteraksi langsung dengan dan memeriksa elemen UI. Hal ini sangat berguna untuk skenario yang melibatkan beberapa jendela, seperti mode Picture-in-Picture (PiP) atau tata letak layar terpisah.
// Find the first window that is in Picture-in-Picture mode
val pipWindow = windows()
.first { it.isInPictureInPictureMode == true }
// Now you can interact with elements within that specific window
pipWindow.onElement { textAsString() == "Play" }.click()
Screenshot dan pernyataan visual
Ambil screenshot seluruh layar, jendela tertentu, atau elemen UI individual langsung dalam pengujian Anda. Hal ini berguna untuk pengujian regresi visual dan proses debug.
uiautomator {
// Take a screenshot of the entire active window
val fullScreenBitmap: Bitmap = activeWindow().takeScreenshot()
fullScreenBitmap.saveToFile(File("/sdcard/Download/full_screen.png"))
// Take a screenshot of a specific UI element (e.g., a button)
val buttonBitmap: Bitmap = onElement { viewIdResourceName == "my_button" }.takeScreenshot()
buttonBitmap.saveToFile(File("/sdcard/Download/my_button_screenshot.png"))
// Example: Take a screenshot of a PiP window
val pipWindowScreenshot = windows()
.first { it.isInPictureInPictureMode == true }
.takeScreenshot()
pipWindowScreenshot.saveToFile(File("/sdcard/Download/pip_screenshot.png"))
}
Fungsi ekstensi saveToFile untuk Bitmap menyederhanakan penyimpanan gambar yang diambil ke jalur yang ditentukan.
Menggunakan ResultsReporter untuk proses debug
ResultsReporter membantu Anda mengaitkan artefak pengujian, seperti screenshot, langsung dengan hasil pengujian di Android Studio untuk memudahkan pemeriksaan dan proses debug.
uiAutomator {
startApp("com.example.targetapp")
val reporter = ResultsReporter("MyTestArtifacts") // Name for this set of results
val file = reporter.addNewFile(
filename = "my_screenshot",
title = "Accessible button image" // Title that appears in Android Studio test results
)
// Take a screenshot of an element and save it using the reporter
onElement { textAsString() == "Accessible button" }
.takeScreenshot()
.saveToFile(file)
// Report the artifacts to instrumentation, making them visible in Android Studio
reporter.reportToInstrumentation()
}
Bermigrasi dari versi UI Automator yang lebih lama
Jika Anda memiliki pengujian UI Automator yang ditulis dengan platform API yang lebih lama, gunakan tabel berikut sebagai referensi untuk bermigrasi ke pendekatan modern:
| Jenis tindakan | Metode UI Automator lama | Metode UI Automator baru |
|---|---|---|
| Titik entri | UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) |
Gabungkan logika pengujian dalam cakupan uiAutomator { ... }. |
| Menemukan elemen UI | device.findObject(By.res("com.example.app:id/my_button")) |
onElement { viewIdResourceName == "my\_button" } |
| Menemukan elemen UI | device.findObject(By.text("Click Me")) |
onElement { textAsString() == "Click Me" } |
| Menunggu UI tidak aktif | device.waitForIdle() |
Sebaiknya gunakan mekanisme waktu tunggu bawaan onElement; jika tidak, activeWindow().waitForStable() |
| Menemukan elemen turunan | Panggilan findObject bertingkat secara manual |
Rantai onElement().onElement() |
| Menangani dialog izin | UiAutomator.registerWatcher() |
watchFor(PermissionDialog) |