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. Dengan ini, Anda dapat menguji versi rilis dengan penerapan minifikasi. UI Automator juga membantu saat menulis pengujian macrobenchmark.
Fitur utama pendekatan modern meliputi:
- Cakupan pengujian
uiAutomator
khusus untuk kode pengujian yang lebih bersih dan ekspresif. - Metode seperti
onElement
,onElements
, danonElementOrNull
untuk menemukan elemen UI dengan predikat yang jelas. - Mekanisme menunggu bawaan untuk elemen bersyarat
onElement*(timeoutMs: Long = 10000)
- Pengelolaan status aplikasi eksplisit seperti
waitForStable
danwaitForAppToBeVisible
. - Interaksi langsung dengan node jendela aksesibilitas untuk skenario pengujian multi-aplikasi.
- Kemampuan screenshot bawaan dan
ResultsReporter
untuk pengujian visual dan proses debug.
Menyiapkan project
Untuk mulai menggunakan API UI Automator modern, perbarui file build.gradle.kts
project Anda 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 API UI Automator modern.
Cakupan pengujian uiAutomator
Akses semua API UI Automator 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 dipilih atau difokuskan, dan deskripsi konten.
onElement { predicate }
: Menampilkan elemen UI pertama yang cocok dengan predikat dalam waktu tunggu default. Fungsi 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 { id == "my_button_id" }.click() // Allow a permission request watchFor(PermissionDialog) { clickAllow() }
onElementOrNull { predicate }
: Mirip denganonElement
, tetapi menampilkannull
jika 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 exists
onElements { 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
:
Menggabungkan panggilan
onElement
untuk elemen bertingkat: Anda dapat menggabungkan panggilanonElement
untuk 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 { id == "first" } .onElement { id == "second" } .onElement { id == "third" } .click()
Tentukan waktu tunggu untuk fungsi
onElement*
dengan meneruskan nilai yang merepresentasikan milidetik.// Find a Ui element with a zero timeout (instant check) onElement(0) { id == "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 menyetel 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 tak 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 handler untuk elemen UI yang tidak terduga, seperti dialog izin, yang mungkin muncul selama alur pengujian. Hal ini menggunakan mekanisme watcher internal, tetapi menawarkan fleksibilitas yang lebih besar.
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 hingga elemen terlihat atau stabil. UI Automator menawarkan beberapa API untuk membantu hal ini.
waitForAppToBeVisible("com.example.targetapp")
menunggu elemen UI dengan
nama paket tertentu 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 { id == "my_loading_indicator" }.waitForStable()
Fitur lanjutan
Fitur berikut berguna untuk skenario pengujian yang lebih kompleks.
Berinteraksi dengan beberapa jendela
UI Automator API memungkinkan Anda berinteraksi dan memeriksa elemen UI secara langsung. 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 dan proses debug regresi visual.
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 { id == "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 permukaan API lama, gunakan tabel berikut sebagai referensi untuk bermigrasi ke pendekatan modern:
Jenis tindakan | Metode UI Automator lama | Metode UI Automator baru |
---|---|---|
Titik awal | UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) |
Gabungkan logika pengujian dalam cakupan uiAutomator { ... } . |
Menemukan elemen UI | device.findObject(By.res("com.example.app:id/my_button")) |
onElement { id == "my\_button" } |
Menemukan elemen UI | device.findObject(By.text("Click Me")) |
onElement { textAsString() == "Click Me" } |
Menunggu UI tidak ada aktivitas | device.waitForIdle() |
Lebih memilih mekanisme waktu tunggu bawaan onElement ; jika tidak, activeWindow().waitForStable() |
Menemukan elemen turunan | Panggilan findObject yang disarangkan secara manual |
onElement().onElement() perantaian |
Menangani dialog izin | UiAutomator.registerWatcher() |
watchFor(PermissionDialog) |