Khung kiểm thử UI Automator cung cấp một tập hợp các API để tạo các chương trình kiểm thử giao diện người dùng mà tương tác với ứng dụng của người dùng và ứng dụng hệ thống.
Giới thiệu về hoạt động kiểm thử 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, được sắp xếp hợp lý, giúp đơn giản hoá việc viết các chương trình kiểm thử giao diện người dùng cho Android. Bề mặt 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 trạng thái ứng dụng. Hãy sử dụng API này để tạo các chương trình kiểm thử tự động đáng tin cậy và dễ bảo 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 đã áp dụng tính năng thu gọn. UI Automator also giúp ích khi viết các chương trình kiểm thử macrobenchmark.
Các tính năng chính của phương pháp hiện đại bao gồm:
- Phạm vi kiểm thử
uiAutomatordành riêng cho mã kiểm thử rõ ràng và biểu cảm hơn. - Các phương thức như
onElement,onElementsvàonElementOrNullđể tìm các thành phần 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) - Tính năng quản lý trạng thái ứng dụng rõ ràng, chẳng hạn như
waitForStablevà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 tình huống kiểm thử nhiều cửa sổ.
- Các tính năng chụp ảnh màn hình tích hợp và một
ResultsReporterđể kiểm thử trực quan và gỡ lỗi.
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 để đưa phần phụ thuộc mới nhất vào:
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ả các 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 uiAutomator { ... }
khối. 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 thao tác kiểm thử.
uiAutomator {
// All your UI Automator actions go here
startApp("com.example.targetapp")
onElement { textAsString() == "Hello, World!" }.click()
}
Tìm các thành phần 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 thành phần 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ề thành phần đầu tiên trên giao diện người dùng 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 xác định được thành phần khớp.// 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 }: Tương tự nhưonElement, nhưng trả vềnullnếu hàm không tìm thấy thành phần khớp nào trong thời gian chờ. Hàm này không gửi ngoại lệ. Sử dụng phương thức này cho các thành phần không bắt buộc.val optionalButton = onElementOrNull { textAsString() == "Skip" } optionalButton?.click() // Click only if the button existsonElements { predicate }: Chờ cho đến khi có ít nhất một thành phần trê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 trê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 các lệnh gọi onElement:
Xâu chuỗi các lệnh gọi
onElementcho các thành phần lồng nhau: Bạn có thể xâu chuỗi các lệnh gọionElementđể tìm các thành phần trong các thành phần 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 { viewIdResourceName == "first" } .onElement { viewIdResourceName == "second" } .onElement { viewIdResourceName == "third" } .click()Chỉ định thời gian chờ cho các hàm
onElement*bằng cách truyền một giá trị đại diện cho mili giây.// 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()
Tương tác với các thành phần trên giao diện người dùng
Tương tác với các thành phần 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 fields.
// 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ý 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 thành phần 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 ứng dụng
Các API cung cấp 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 trình xử lý cho các thành phần không mong muốn trên giao diện người dùng,
chẳng hạn như hộp thoại quyền có thể xuất hiện trong luồng kiểm thử. API này
sử dụng cơ chế trình theo dõi nội bộ nhưng mang lại sự linh hoạt 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 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ờ cho ứng dụng hiển thị và ổn định
Đôi khi, các chương trình kiểm thử cần chờ cho các thành phần trở nên hiển thị hoặc ổn định. UI Automator cung cấp một số API để giúp bạn thực hiện việc này.
waitForAppToBeVisible("com.example.targetapp") chờ cho 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 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 { viewIdResourceName == "my_loading_indicator" }.waitForStable()
Sử dụng UI Automator cho Macrobenchmark và Hồ sơ cơ sở
Sử dụng UI Automator để kiểm thử hiệu suất bằng Jetpack Macrobenchmark và để tạo Hồ sơ cơ sở, vì API này cung cấp một cách đáng tin cậy để tương tác với ứng dụng và đo lường hiệu suất từ góc độ người dùng cuối.
Macrobenchmark sử dụng các API UI Automator để điều khiển giao diện người dùng và đo lường các hoạt động tương tác.
Ví dụ: trong các điểm chuẩn khởi động, bạn có thể sử dụng onElement để phát hiện thời điểm nội dung giao diện người dùng
được tải đầy đủ, cho phép bạn đo lường Thời gian hiển thị đầy đủ
(TTFD). Trong các điểm chuẩn giật, các API UI Automator được dùng để cuộn danh sách hoặc
chạy ảnh động nhằm đo lường thời gian khung hình. Các hàm như startActivity() hoặc
startIntent() rất hữu ích để đưa ứng dụng vào trạng thái chính xác trước khi
bắt đầu đo lường.
Khi tạo Hồ sơ cơ sở, bạn sẽ tự động hoá hành trình quan trọng của người dùng (CUJ) của ứng dụng để ghi lại những lớp và phương thức nào cần biên dịch trước. UI
Automator là một công cụ lý tưởng để viết các tập lệnh tự động hoá này. Cơ chế tìm phần tử dựa trên vị từ và cơ chế chờ tích hợp của DSL hiện đại (onElement)
dẫn đến việc thực thi chương trình kiểm thử mạnh mẽ và mang tính xác định hơn so với các phương thức khác.
Tính ổn định này giúp giảm tình trạng không ổn định và đảm bảo rằng Hồ sơ cơ sở được tạo
phản ánh chính xác các đường dẫn mã được thực thi trong các luồng người dùng quan trọng nhất.
Các tính năng nâng cao
Các tính năng sau đây rất hữu ích cho các tình huống kiểm thử phức tạp hơn.
Tương tác với nhiều cửa sổ
Các API UI Automator cho phép bạn tương tác trực tiếp và kiểm tra các thành phần trên giao diện người dùng. Điều này đặc biệt hữu ích cho các tình huống 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à 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 thành phần riêng lẻ trên giao diện người dùng trực tiếp trong các chương trình kiểm thử. Điều này hữu ích cho việc kiểm thử và gỡ lỗi hồi quy trực quan.
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"))
}
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 chỉ định.
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 hơn.
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ũ hơn
Nếu bạn có các chương trình kiểm thử UI Automator hiện có được viết bằng các bề mặt API cũ hơn, hãy sử dụng bảng sau đây 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 thành phần trên giao diện người dùng | device.findObject(By.res("com.example.app:id/my_button")) |
onElement { viewIdResourceName == "my\_button" } |
| Tìm các thành phần trên giao diện người dùng | device.findObject(By.text("Click Me")) |
onElement { textAsString() == "Click Me" } |
| Chờ cho 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 sử dụng activeWindow().waitForStable() |
| Tìm các thành phần con | Các lệnh gọi được lồng theo cách thủ côngfindObject |
onElement().onElement() xâu chuỗi |
| Xử lý hộp thoại quyền | UiAutomator.registerWatcher() |
watchFor(PermissionDialog) |