Khung kiểm thử UI Automator cung cấp một bộ API để tạo các quy trình kiểm thử giao diện người dùng tương tác với ứng dụng người dùng và ứng dụng hệ thống.
Giới thiệu về hoạt động kiểm thử bằng UI Automator hiện đại
UI Automator 2.4 giới thiệu Ngôn ngữ dành riêng cho miền (DSL) thân thiện với Kotlin và được tinh giản, giúp đơn giản hoá việc viết các kiểm thử giao diện người dùng cho Android. Nền tảng API mới này tập trung vào việc tìm phần tử dựa trên vị từ và kiểm soát rõ ràng các trạng thái ứng dụng. Sử dụng tính năng này để tạo các kiểm thử tự động đáng tin cậy và dễ duy trì hơn.
UI Automator cho phép bạn kiểm thử một ứng dụng từ bên ngoài quy trình của ứng dụng. Điều này cho phép bạn kiểm thử các phiên bản phát hành có áp dụng tính năng rút gọn. UI Automator cũng giúp ích khi viết các kiểm thử macrobenchmark.
Các tính năng chính của phương pháp hiện đại bao gồm:
- Một phạm vi kiểm thử
uiAutomator
chuyên biệt để có mã kiểm thử rõ ràng và biểu cảm hơn. - Các phương thức như
onElement
,onElements
vàonElementOrNull
để tìm các phần tử trên giao diện người dùng bằng các vị từ rõ ràng. - Cơ chế chờ tích hợp cho các phần tử có điều kiện
onElement*(timeoutMs: Long = 10000)
- Quản lý trạng thái ứng dụng một cách tường minh, chẳng hạn như
waitForStable
vàwaitForAppToBeVisible
. - Tương tác trực tiếp với các nút cửa sổ hỗ trợ tiếp cận cho các trường hợp kiểm thử nhiều cửa sổ.
- Khả năng chụp ảnh màn hình tích hợp và
ResultsReporter
để kiểm thử và gỡ lỗi trực quan.
Thiết lập dự án
Để bắt đầu sử dụng các API UI Automator hiện đại, hãy cập nhật tệp build.gradle.kts
của dự án để thêm phần phụ thuộc mới nhất:
Kotlin
dependencies {
...
androidTestImplementation("androidx.test.uiautomator:uiautomator:2.4.0-alpha05")
}
Groovy
dependencies {
...
androidTestImplementation "androidx.test.uiautomator:uiautomator:2.4.0-alpha05"
}
Các khái niệm cốt lõi về API
Các phần sau đây mô tả những khái niệm cốt lõi của API UI Automator hiện đại.
Phạm vi kiểm thử uiAutomator
Truy cập vào tất cả các API UI Automator mới trong khối uiAutomator { ... }
. Hàm này tạo một UiAutomatorTestScope
cung cấp một môi trường ngắn gọn và an toàn về kiểu cho các hoạt động kiểm thử của bạn.
uiAutomator {
// All your UI Automator actions go here
startApp("com.example.targetapp")
onElement { textAsString() == "Hello, World!" }.click()
}
Tìm các phần tử trên giao diện người dùng
Sử dụng các API UI Automator với các vị từ để xác định vị trí của các phần tử trên giao diện người dùng. Các vị từ này cho phép bạn xác định các điều kiện cho các thuộc tính như văn bản, trạng thái đã chọn hoặc trạng thái được lấy tiêu điểm và nội dung mô tả.
onElement { predicate }
: Trả về phần tử giao diện người dùng đầu tiên khớp với vị từ trong thời gian chờ mặc định. Hàm này sẽ gửi một ngoại lệ nếu không tìm thấy phần tử phù hợp.// 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 }
: Tương tự nhưonElement
, nhưng trả vềnull
nếu hàm không tìm thấy phần tử nào khớp trong thời gian chờ. Hệ thống sẽ không gửi một trường hợp ngoại lệ. Hãy dùng phương thức này cho các phần tử không bắt buộc.val optionalButton = onElementOrNull { textAsString() == "Skip" } optionalButton?.click() // Click only if the button exists
onElements { predicate }
: Chờ cho đến khi có ít nhất một thành phần giao diện người dùng khớp với vị từ đã cho, sau đó trả về danh sách tất cả các thành phần giao diện người dùng khớp.// Get all items in a list Ui element val listItems = onElements { className == "android.widget.TextView" && isClickable } listItems.forEach { it.click() }
Dưới đây là một số mẹo sử dụng cuộc gọi onElement
:
Chuỗi các lệnh gọi
onElement
cho các phần tử lồng nhau: Bạn có thể tạo chuỗi các lệnh gọionElement
để tìm các phần tử trong các phần tử khác, theo hệ thống phân cấp cha-con.// 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()
Chỉ định thời gian chờ cho các hàm
onElement*
bằng cách truyền một giá trị biểu thị mili giây.// 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()
Tương tác với các phần tử giao diện người dùng
Tương tác với các phần tử trên giao diện người dùng bằng cách mô phỏng các lượt nhấp hoặc đặt văn bản trong các trường có thể chỉnh sửa.
// 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()
Xử lý các trạng thái và trình theo dõi ứng dụng
Quản lý vòng đời của ứng dụng và xử lý các phần tử không mong muốn trên giao diện người dùng có thể xuất hiện trong quá trình kiểm thử.
Quản lý vòng đời của ứng dụng
Các API này cung cấp những cách để kiểm soát trạng thái của ứng dụng đang kiểm thử:
// 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")
Xử lý giao diện người dùng không mong muốn
API watchFor
cho phép bạn xác định các trình xử lý cho những phần tử không mong muốn trên giao diện người dùng (chẳng hạn như hộp thoại cấp quyền) có thể xuất hiện trong quy trình kiểm thử. Phương thức này sử dụng cơ chế trình theo dõi nội bộ nhưng mang lại tính linh hoạt cao hơn.
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
là một ví dụ về ScopedWatcher<T>
, trong đó T
là đối tượng được truyền dưới dạng một phạm vi đến khối trong watchFor
. Bạn có thể tạo trình theo dõi tuỳ chỉnh dựa trên mẫu này.
Chờ khả năng hiển thị và độ ổn định của ứng dụng
Đôi khi, các kiểm thử cần đợi cho đến khi các phần tử xuất hiện hoặc ổn định. UI Automator cung cấp một số API để hỗ trợ việc này.
waitForAppToBeVisible("com.example.targetapp")
đợi một thành phần trên giao diện người dùng có tên gói đã cho xuất hiện trên màn hình trong một khoảng thời gian chờ có thể tuỳ chỉnh.
// Wait for the app to be visible after launching it
startApp("com.example.targetapp")
waitForAppToBeVisible("com.example.targetapp")
Sử dụng API waitForStable()
để xác minh rằng giao diện người dùng của ứng dụng được coi là ổn định trước khi tương tác với giao diện đó.
// 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()
Các tính năng nâng cao
Các tính năng sau đây rất hữu ích cho những tình huống kiểm thử phức tạp hơn.
Tương tác với nhiều cửa sổ
API UI Automator cho phép bạn tương tác trực tiếp và kiểm tra các phần tử trên giao diện người dùng. Điều này đặc biệt hữu ích trong các trường hợp liên quan đến nhiều cửa sổ, chẳng hạn như chế độ Hình trong hình (PiP) hoặc bố cục chia đôi màn hình.
// 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()
Ảnh chụp màn hình và câu khẳng định trực quan
Chụp ảnh màn hình toàn bộ màn hình, các cửa sổ cụ thể hoặc các phần tử giao diện người dùng riêng lẻ ngay trong các thử nghiệm của bạn. Điều này rất hữu ích cho việc kiểm thử hồi quy trực quan và gỡ lỗi.
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"))
}
Hàm tiện ích saveToFile
cho Bitmap giúp đơn giản hoá việc lưu hình ảnh đã chụp vào một đường dẫn cụ thể.
Sử dụng ResultsReporter để gỡ lỗi
ResultsReporter
giúp bạn liên kết các cấu phần phần mềm kiểm thử (chẳng hạn như ảnh chụp màn hình) trực tiếp với kết quả kiểm thử trong Android Studio để dễ dàng kiểm tra và gỡ lỗi.
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()
}
Di chuyển từ các phiên bản UI Automator cũ
Nếu bạn có các kiểm thử UI Automator hiện có được viết bằng các giao diện API cũ, hãy sử dụng bảng sau làm tài liệu tham khảo để di chuyển sang phương pháp hiện đại:
Loại thao tác | Phương thức UI Automator cũ | Phương thức UI Automator mới |
---|---|---|
Điểm truy cập | UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) |
Gói logic kiểm thử trong phạm vi uiAutomator { ... } . |
Tìm các phần tử trên giao diện người dùng | device.findObject(By.res("com.example.app:id/my_button")) |
onElement { id == "my\_button" } |
Tìm các phần tử trên giao diện người dùng | device.findObject(By.text("Click Me")) |
onElement { textAsString() == "Click Me" } |
Đợi giao diện người dùng ở trạng thái rảnh | device.waitForIdle() |
Ưu tiên cơ chế thời gian chờ tích hợp của onElement ; nếu không, hãy dùng activeWindow().waitForStable() |
Tìm phần tử con | Cuộc gọi findObject được lồng theo cách thủ công |
onElement().onElement() xâu chuỗi |
Xử lý hộp thoại quyền | UiAutomator.registerWatcher() |
watchFor(PermissionDialog) |