UI Automator 測試架構提供一組 API,可建構與使用者應用程式和系統應用程式互動的 UI 測試。
新版 UI Automator 測試簡介
UI Automator 2.4 推出簡化的 Kotlin 友善領域特定語言 (DSL),可簡化 Android 的 UI 測試編寫作業。這個新 API 介面著重於以述詞為基礎的元素尋找作業,以及對應用程式狀態的明確控制。您可以使用這項功能,建立更易於維護且可靠的自動化測試。
您可以使用 UI Automator 從應用程式程序外部測試應用程式。這樣您就能測試已套用縮減功能的發布版本。編寫巨集基準測試時,UI Automator 也很有幫助。
現代方法的關鍵功能包括:
- 專屬
uiAutomator
測試範圍,可讓測試程式碼更簡潔且更具表達力。 - 使用
onElement
、onElements
和onElementOrNull
等方法,透過明確的述詞尋找 UI 元素。 - 條件式元素
onElement*(timeoutMs: Long = 10000)
的內建等待機制 - 明確的應用程式狀態管理,例如
waitForStable
和waitForAppToBeVisible
。 - 直接與無障礙視窗節點互動,測試多視窗情境。
- 內建螢幕截圖功能,以及用於視覺測試和偵錯的
ResultsReporter
。
設定專案
如要開始使用新版 UI Automator API,請更新專案的 build.gradle.kts
檔案,加入最新依附元件:
Kotlin
dependencies {
...
androidTestImplementation("androidx.test.uiautomator:uiautomator:2.4.0-alpha05")
}
Groovy
dependencies {
...
androidTestImplementation "androidx.test.uiautomator:uiautomator:2.4.0-alpha05"
}
核心 API 概念
以下各節說明新版 UI Automator API 的核心概念。
uiAutomator 測試範圍
存取 uiAutomator { ... }
區塊中的所有新版 UI Automator API。這個函式會建立 UiAutomatorTestScope
,為測試作業提供簡潔且型別安全的環境。
uiAutomator {
// All your UI Automator actions go here
startApp("com.example.targetapp")
onElement { textAsString() == "Hello, World!" }.click()
}
尋找 UI 元素
使用 UI Automator API 和述詞尋找 UI 元素。這些述詞可讓您定義屬性的條件,例如文字、選取或焦點狀態,以及內容說明。
onElement { predicate }
:傳回在預設逾時時間內符合述詞的第一個 UI 元素。如果找不到相符的元素,函式就會擲回例外狀況。// 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 }
:與onElement
類似,但如果函式在逾時前找不到相符的元素,就會傳回null
。不會擲回例外狀況。選用元素請使用這個方法。val optionalButton = onElementOrNull { textAsString() == "Skip" } optionalButton?.click() // Click only if the button exists
onElements { predicate }
:等待至少一個 UI 元素符合指定述詞,然後傳回所有相符 UI 元素的清單。// Get all items in a list Ui element val listItems = onElements { className == "android.widget.TextView" && isClickable } listItems.forEach { it.click() }
以下是使用 onElement
通話的幾個訣竅:
巢狀元素的鏈結
onElement
呼叫:您可以鏈結onElement
呼叫,在其他元素中尋找元素,並遵循父項/子項階層。// 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()
傳遞代表毫秒的值,為
onElement*
函式指定逾時。// 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()
與 UI 元素互動
模擬點擊或在可編輯欄位中設定文字,與 UI 元素互動。
// 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()
處理應用程式狀態和監看程式
管理應用程式的生命週期,並處理測試期間可能出現的非預期 UI 元素。
應用程式生命週期管理
這些 API 提供控管受測應用程式狀態的方法:
// 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")
處理非預期的 UI
watchFor
API 可讓您定義非預期的 UI 元素 (例如權限對話方塊) 的處理常式,這些元素可能會在測試流程中顯示。這會使用內部監控機制,但彈性更高。
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
是 ScopedWatcher<T>
的範例,其中 T
是以範圍形式傳遞至 watchFor
中區塊的物件。您可以根據這個模式建立自訂監控程式。
等待應用程式顯示和穩定
有時測試需要等待元素顯示或穩定。UI Automator 提供多項 API,可協助您完成這項工作。
waitForAppToBeVisible("com.example.targetapp")
會等待具有指定套件名稱的 UI 元素在可自訂的逾時時間內顯示在畫面上。
// Wait for the app to be visible after launching it
startApp("com.example.targetapp")
waitForAppToBeVisible("com.example.targetapp")
使用 waitForStable()
API 驗證應用程式的 UI 是否穩定,再與其互動。
// 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()
進階功能
下列功能適用於較複雜的測試情境。
與多個視窗互動
您可以使用 UI Automator API 直接與 UI 元素互動及檢查。這在涉及多個視窗的情境中特別實用,例如子母畫面 (PiP) 模式或分割畫面版面配置。
// 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()
螢幕截圖和視覺斷言
直接在測試中擷取整個畫面、特定視窗或個別 UI 元素的螢幕截圖。這有助於進行視覺迴歸測試和偵錯。
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"))
}
Bitmap 的 saveToFile
擴充功能函式可簡化將擷取的圖片儲存至指定路徑的程序。
使用 ResultsReporter 進行偵錯
ResultsReporter
可協助您將測試構件 (例如螢幕截圖) 直接與 Android Studio 中的測試結果建立關聯,方便檢查及偵錯。
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()
}
從舊版 UI Automator 遷移
如果您有使用舊版 API 介面編寫的現有 UI Automator 測試,請參考下表,改用新式方法:
動作類型 | 舊版 UI Automator 方法 | 新的 UI Automator 方法 |
---|---|---|
進入點 | UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) |
將測試邏輯包裝在 uiAutomator { ... } 範圍內。 |
尋找 UI 元素 | device.findObject(By.res("com.example.app:id/my_button")) |
onElement { id == "my\_button" } |
尋找 UI 元素 | device.findObject(By.text("Click Me")) |
onElement { textAsString() == "Click Me" } |
等待閒置的 UI | device.waitForIdle() |
Prefer onElement 's built-in timeout mechanism; otherwise, activeWindow().waitForStable() |
尋找子元素 | 手動巢狀 findObject 呼叫 |
onElement().onElement() 鏈結 |
處理權限對話方塊 | UiAutomator.registerWatcher() |
watchFor(PermissionDialog) |