UI Automator là một framework của Google dành cho kiểm thử UI tự động các ứng dụng Android, hoạt động ở cấp hệ thống và có thể tương tác với các phần tử giao diện bên ngoài một ứng dụng đơn lẻ. Không giống Espresso, UI Automator không bị ràng buộc với tiến trình của một ứng dụng cụ thể: nó có thể mở hộp thoại hệ thống, bảng thông báo và chuyển đổi giữa các ứng dụng. Theo Google Android Developers, UI Automator sử dụng Accessibility Service tiêu chuẩn để truy cập cây UI của thiết bị.
Những điểm chính
UI Automator là một framework kiểm thử UI chức năng cho Android hoạt động ở cấp hệ điều hành. Nó cung cấp API để truy cập bất kỳ phần tử nào trên màn hình thiết bị, bất kể nó thuộc ứng dụng nào — bao gồm thanh trạng thái hệ thống, hộp thoại quyền, màn hình chính và ứng dụng của bên thứ ba. Điều này làm cho nó không thể thiếu để kiểm thử các kịch bản vượt ra ngoài một ứng dụng đơn lẻ.
Về mặt kiến trúc, UI Automator sử dụng Accessibility Service — cùng dịch vụ được TalkBack, Switch Access và các công cụ trợ năng khác sử dụng. Thông qua dịch vụ này, framework lấy được cây thành phần UI đầy đủ của màn hình hiện tại và cho phép thực hiện các hành động trên chúng: chạm, vuốt, nhập văn bản và nhấn giữ.
UI Automator xuất hiện lần đầu trong Android 4.3 (API 18) và từ đó trở thành một phần của Android Testing Support Library như công cụ chính thức của Google cho kiểm thử đa ứng dụng. Trong AndroidX Test, nó có sẵn dưới dạng artifact riêng androidx.test.uiautomator:uiautomator phiên bản 2.3.0 (2024), hỗ trợ tất cả các phiên bản Android từ API 18.
Nguyên lý hoạt động: UI Automator dựa trên việc quét cây trợ năng của màn hình hiện tại. Khi phương thức findObject(selector) được gọi, framework duyệt qua hệ thống phân cấp View, tìm phần tử đầu tiên khớp với điều kiện của UiSelector và trả về một UiObject — proxy để tương tác với View thực tế.
Một kiểm thử UI Automator điển hình bắt đầu bằng cách lấy một phiên bản UiDevice, đại diện cho thiết bị vật lý. UiDevice cung cấp các phương thức để tìm phần tử, quản lý nhấn nút (Home, Back, Recent), xoay màn hình và chụp ảnh màn hình. Sau khi tìm thấy phần tử qua UiSelector, các hành động được thực hiện trên UiObject.
Trong ví dụ dưới đây, kiểm thử mở ứng dụng Cài đặt, tìm mục “Pin” bằng văn bản và chạm vào nó. UI Automator không yêu cầu khởi chạy Activity — nó hoạt động với bất kỳ màn hình nào trên thiết bị, bao gồm cả ứng dụng của bên thứ ba.
val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
// Mở màn hình cài đặt
device.pressHome()
device.wait(Until.hasObject(UiSelector().text("Cài đặt")), 2000)
// Tìm mục "Pin" và chạm
val batteryItem = device.findObject(
UiSelector().text("Pin")
)
batteryItem.clickAndWait(Until.newWindow(), 3000)
UiDevice là lớp chính để tương tác với thiết bị. Nó cung cấp các phương thức để tìm phần tử, mô phỏng nhấn nút phần cứng (Home, Back, Menu, Volume), quản lý nguồn, chụp ảnh màn hình và chờ các trạng thái màn hình cụ thể. UiDevice được tạo một lần cho mỗi kiểm thử và tái sử dụng cho tất cả các thao tác.
UiSelector là một API mềm dẻo để tìm phần tử UI. Không giống ViewMatchers của Espresso, UiSelector không yêu cầu biên dịch — các điều kiện tìm kiếm được hình thành thông qua chuỗi phương thức: text(), className(), description(), resourceId(), index(). Nhiều điều kiện được kết hợp tự động thông qua AND logic.
| Phương thức UiSelector | Mục đích |
|---|---|
| text(String) | Tìm theo văn bản chính xác của phần tử |
| textContains(String) | Tìm theo khớp một phần văn bản |
| resourceId(String) | Tìm theo ID tài nguyên (ví dụ: com.example:id/button) |
| className(String) | Tìm theo tên lớp View |
| description(String) | Tìm theo content-description |
| childSelector(selector) | Tìm phần tử con trong một bộ chứa |
Khi có nhiều phần tử trên màn hình có cùng văn bản, UiSelector cho phép kết hợp các tiêu chí: tìm bộ chứa theo ID, sau đó bên trong nó — phần tử theo văn bản và lớp. Điều này đảm bảo nhận dạng duy nhất của thành phần mong muốn. Phương thức childSelector thu hẹp phạm vi tìm kiếm đến một bộ chứa cụ thể, tăng tốc điều hướng qua cây UI.
val scrollView = device.findObject(
UiSelector().resourceId("android:id/list")
)
// Trong danh sách, tìm phần tử có văn bản "Wi-Fi"
val wifiItem = scrollView.findObject(
UiSelector().text("Wi-Fi")
wifiItem.click()
Kiểm thử đa ứng dụng (liên ứng dụng) là tính năng chính mà UI Automator được lựa chọn. Framework có thể chuyển đổi giữa các ứng dụng, kiểm thử đăng nhập OAuth qua trình duyệt, kiểm tra hộp thoại hệ thống (quyền, bộ chọn ứng dụng) và tương tác với thanh trạng thái hệ thống, bảng thông báo và màn hình khóa.
Một kịch bản kiểm thử đa ứng dụng điển hình: ứng dụng mở trình duyệt để ủy quyền OAuth, người dùng nhập tên đăng nhập và mật khẩu, trình duyệt chuyển hướng trở lại ứng dụng. UI Automator chuyển đổi giữa các tiến trình, tìm trường nhập trong trình duyệt, điền chúng và chạm “Đăng nhập”.
// Đợi trình duyệt xuất hiện
device.wait(Until.hasObject(
UiSelector().packageName("com.android.chrome")
), 5000)
// Tìm trường nhập email trong trình duyệt
val emailField = device.findObject(
UiSelector().className("android.widget.EditText").instance(0)
)
emailField.text = "user@example.com"
UI Automator có thể kiểm tra và đóng hộp thoại hệ thống — quyền vị trí, thông báo, truy cập tệp. Điều này cực kỳ quan trọng để kiểm thử các kịch bản khởi chạy lần đầu khi hệ thống yêu cầu tuần tự nhiều quyền. Nếu không có UI Automator, các kịch bản này không thể tự động hóa vì hộp thoại hệ thống không thuộc tiến trình ứng dụng.
Sự lựa chọn giữa UI Automator và Espresso phụ thuộc vào kịch bản kiểm thử. Espresso được tối ưu hóa cho kiểm thử một ứng dụng đơn lẻ với đồng bộ tự động và boilerplate tối thiểu. UI Automator phù hợp cho các kịch bản cần tương tác với hệ thống, trình duyệt hoặc nhiều ứng dụng.
| Tiêu chí | UI Automator | Espresso |
|---|---|---|
| Phạm vi | Toàn bộ thiết bị, nhiều ứng dụng | Một ứng dụng |
| Đồng bộ | Thủ công (chờ, ngủ) | Tự động (Idling Resource) |
| Tốc độ | Chậm hơn (truy cập qua dịch vụ) | Nhanh hơn (hoạt động trong tiến trình) |
| Giao diện hệ thống | Hỗ trợ (Thông báo, Cài đặt nhanh) | Không hỗ trợ |
| Độ chính xác tìm kiếm | UiSelector theo thuộc tính | ViewMatchers theo loại và hệ thống phân cấp |
| Độ ổn định | Thấp hơn (phụ thuộc vào thời gian) | Cao hơn (chờ tự động) |
Trong thực tế, các framework này thường được sử dụng cùng nhau: Espresso bao phủ kiểm thử UI của ứng dụng chính với độ ổn định cao, trong khi UI Automator được sử dụng cho các kịch bản vượt ra ngoài ranh giới ứng dụng — đăng nhập OAuth, quyền hệ thống, làm việc với Share Intent. Sự kết hợp này mang lại phạm vi bao phủ UI tối đa với chi phí bảo trì kiểm thử tối thiểu.
Tích hợp UI Automator được thực hiện bằng cách thêm phụ thuộc vào build.gradle. Framework là một phần của AndroidX Test và không yêu cầu quyền bổ sung trong tệp kê khai — quyền truy cập vào Accessibility Service được cấu hình tự động khi khởi chạy kiểm thử công cụ.
Cấu hình tối thiểu bao gồm artifact uiautomator và trình chạy kiểm thử tiêu chuẩn AndroidJUnitRunner. Các kiểm thử UI Automator được đặt trong thư mục src/androidTest và chạy trên trình giả lập hoặc thiết bị vật lý chạy Android API 18+.
dependencies {
androidTestImplementation("androidx.test.uiautomator:uiautomator:2.3.0")
androidTestImplementation("androidx.test.ext:junit:1.2.1")
androidTestImplementation("androidx.test:runner:1.6.1")
}
Để lấy một phiên bản UiDevice, sử dụng InstrumentationRegistry.getInstrumentation(). UiDevice nên được tạo một lần trong phương thức setUp() và tái sử dụng trong tất cả các kiểm thử của lớp để tiết kiệm tài nguyên thiết bị. Cần lưu ý rằng UiDevice không an toàn luồng — tất cả các thao tác phải được thực hiện trong cùng một luồng của phương thức kiểm thử. Tạo UiDevice mới trong mỗi kiểm thử gây ra chi phí và làm chậm quá trình thực thi. Khuyến nghị tạo UiDevice một lần trong phương thức beforeClass và tái sử dụng cho tất cả các kiểm thử của lớp kiểm thử.
Không giống Espresso, UI Automator không có đồng bộ tự động. Để chờ các phần tử xuất hiện, sử dụng phương thức UiDevice.wait(condition, timeout) với đối tượng Until: Until.findObject(selector), Until.hasObject(selector), Until.gone(selector). Nếu không chờ đợi thích hợp, các kiểm thử trở nên không ổn định do điều kiện cạnh tranh — phần tử có thể chưa xuất hiện trên màn hình tại thời điểm tìm kiếm. Khuyến nghị đặt thời gian chờ tối thiểu 3–5 giây để đảm bảo ổn định.
Các câu hỏi thường gặp
UI Automator hoạt động ở cấp Accessibility Service và có thể tương tác với bất kỳ ứng dụng nào. Espresso hoạt động trong tiến trình của một ứng dụng và sử dụng đồng bộ tự động với luồng UI. UI Automator phù hợp hơn cho kịch bản đa ứng dụng, Espresso phù hợp hơn cho kiểm thử ổn định của một ứng dụng.
Có, UI Automator hoạt động trên tất cả các thiết bị chạy Android API 18+. Nó không yêu cầu quyền root — nó sử dụng Accessibility Service tiêu chuẩn, được kích hoạt qua Instrumentation khi khởi chạy kiểm thử.
UI Automator sử dụng Accessibility Service để lấy cây thành phần UI đầy đủ của màn hình hiện tại. Sau đó UiSelector duyệt qua cây này và tìm phần tử theo các tiêu chí đã chỉ định: văn bản, lớp, ID, content-description hoặc kết hợp của chúng.
Có, phương thức UiDevice.takeScreenshot(storePath) cho phép chụp ảnh màn hình hiện tại và lưu vào tệp. Điều này hữu ích cho việc gỡ lỗi: khi kiểm thử thất bại, bạn có thể lưu ảnh màn hình và phân tích trạng thái màn hình.
UI Automator không có đồng bộ tự động, do đó kiểm thử nhạy cảm với thời gian. Nếu hoạt ảnh chưa kết thúc hoặc View chưa được hiển thị, findObject có thể không tìm thấy phần tử. Giải pháp là sử dụng UiDevice.wait() với thời gian chờ đủ.
Tổng kết
Bộ công cụ UI Automator bao phủ tất cả các kịch bản kiểm thử đa ứng dụng chính và là tiêu chuẩn cho tự động hóa Android ở cấp hệ thống.
Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay
IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.
Đọc thêm