Kiểm thử UI kiểm tra tính chính xác của việc hiển thị và tương tác của các phần tử giao diện người dùng trong ứng dụng di động — nút bấm, trường văn bản, danh sách và thành phần điều hướng. Không giống như kiểm thử đơn vị kiểm tra logic nghiệp vụ, kiểm thử UI mô phỏng hành động của người dùng: chạm, vuốt, nhập văn bản và kiểm tra phản hồi của giao diện. Theo một nghiên cứu của Android Developers, 2024, kiểm thử UI bao phủ 70% kịch bản người dùng quan trọng và cho phép phát hiện lỗi bố cục mà các kiểm tra logic không thể phát hiện.
Những điểm chính
Kiểm thử UI là một loại kiểm tra tự động trong đó mã kiểm thử tương tác với giao diện đồ họa của ứng dụng giống như người dùng thực. Kiểm thử tìm một phần tử trên màn hình — nút bấm, trường văn bản, danh sách — thực hiện hành động trên đó và kiểm tra phản hồi mong đợi của giao diện. Ví dụ, sau khi nhập mật khẩu sai, kiểm thử UI kiểm tra xem thông báo lỗi với nội dung chính xác có xuất hiện trên màn hình hay không.
Sự khác biệt chính giữa kiểm thử UI và các loại tự động hóa khác là chúng hoạt động thông qua lớp trợ năng của hệ điều hành, không phải qua API nội bộ của ứng dụng. Điều này có nghĩa là kiểm thử UI nhìn thấy giao diện chính xác như người dùng và trình đọc màn hình. Nhờ đó, kiểm thử UI không chỉ kiểm tra chức năng mà còn kiểm tra khả năng truy cập của các phần tử — tuân thủ yêu cầu WCAG.
Theo khảo sát JetBrains Developer Ecosystem 2023, 58% đội ngũ di động sử dụng kiểm thử UI trong đường ống CI/CD. Độ bao phủ kiểm thử UI trung bình trong các dự án thương mại là 30–40% số màn hình ứng dụng. Các dự án có kiểm thử UI nhận được ít hơn 25% đánh giá tiêu cực trên cửa hàng ứng dụng liên quan đến lỗi giao diện.
Sự khác biệt chính giữa kiểm thử UI và kiểm thử đơn vị là mức độ trừu tượng. Kiểm thử đơn vị làm việc với các lớp và hàm riêng lẻ, cách ly khỏi framework Android hoặc iOS. Chúng chạy trên JVM (cho Android) mà không cần khởi động trình giả lập và mất mili giây. Kiểm thử UI chạy trên thiết bị thật hoặc trình giả lập, tương tác với dịch vụ hệ thống và mất giây hoặc phút cho mỗi kịch bản.
Đối tượng mục tiêu của kiểm thử cũng khác nhau. Kiểm thử UI kiểm tra các kịch bản người dùng đầu cuối — đăng ký, đặt hàng, tìm kiếm. Kiểm thử đơn vị bao phủ logic nghiệp vụ: tính toán, xác thực, chuyển đổi dữ liệu. Kiểm thử UI không kiểm tra tính chính xác của phép tính thuế — nó kiểm tra tổng số tiền có hiển thị trên màn hình hay không. Bản thân phép tính được kiểm tra bởi kiểm thử đơn vị.
Theo Google Testing Blog (2020), tỷ lệ kiểm thử tối ưu trong một dự án tuân theo quy tắc kim tự tháp kiểm thử: 70% kiểm thử đơn vị, 20% kiểm thử tích hợp và 10% kiểm thử UI. Vi phạm tỷ lệ này theo hướng có lợi cho kiểm thử UI dẫn đến tăng thời gian chạy và độ mong manh của bộ kiểm thử, vì kiểm thử UI nhạy cảm với thay đổi trong bố cục màn hình.
Cho Android, framework thống trị là Espresso — thư viện của Google được tích hợp trong AndroidX Test. Espresso tự động đồng bộ hóa với luồng UI, chờ hoàn thành hoạt ảnh và tác vụ nền trước khi thực hiện kiểm tra tiếp theo. Cho Jetpack Compose, phần mở rộng Compose UI Test được sử dụng, hoạt động thông qua các nút ngữ nghĩa thay vì định danh view truyền thống.
Cho iOS, công cụ chính là XCUITest, một phần của Xcode. Các kiểm thử được viết bằng Swift và sử dụng định danh trợ năng để tìm phần tử. XCUITest hỗ trợ ghi kiểm thử qua chức năng ghi và tích hợp với hệ thống CI qua xcodebuild. Cho các dự án đa nền tảng, Appium được sử dụng, dựa trên giao thức WebDriver và cho phép chạy cùng kiểm thử trên Android và iOS với thay đổi mã tối thiểu.
Espresso hoạt động với hệ thống View truyền thống qua onView và định danh ID tài nguyên. Compose UI Test sử dụng lớp ngữ nghĩa, làm cho kiểm thử ít phụ thuộc vào hệ thống phân cấp view. Ví dụ, tìm nút trong Espresso: onView(withId(R.id.submit)), trong Compose: onNodeWithTag(“submit”). Kiểm thử Compose tự động xử lý tái tổ hợp và không yêu cầu chờ trạng thái rõ ràng.
XCUITest sử dụng XCUIApplication làm điểm vào. Mỗi phần tử giao diện được tìm qua thuộc tính trợ năng: accessibilityIdentifier cho truy cập lập trình và accessibilityLabel cho VoiceOver. Framework hỗ trợ ghi kiểm thử qua chức năng ghi của Xcode — nhà phát triển thực hiện hành động trên trình mô phỏng và Xcode tạo mã kiểm thử. Các kiểm thử sẵn sàng được chạy qua xcodebuild test.
Appium dựa trên giao thức WebDriver và hỗ trợ mọi ngôn ngữ: Java, Python, JavaScript. Chiến lược tìm phần tử bao gồm id, xpath, class name và accessibility id. Appium yêu cầu cài đặt máy chủ và cấu hình Desired Capabilities — platformName, deviceName, appPackage. Một giải pháp thay thế là Maestro, sử dụng kịch bản YAML và không yêu cầu biên dịch mã kiểm thử.
Hãy xem kiểm thử UI cho cùng một kịch bản — đăng nhập vào ứng dụng — trên ba framework khác nhau: Espresso cho Android, XCUITest cho iOS và Appium cho phương pháp đa nền tảng. Kịch bản: nhập tên đăng nhập và mật khẩu, nhấn nút đăng nhập, kiểm tra hiển thị thông báo chào mừng.
Kiểm thử Espresso sử dụng onView để tìm phần tử theo định danh và perform để thực hiện hành động. Phương thức check với bộ so khớp isDisplayed xác nhận phần tử hiển thị trên màn hình.
@RunWith(AndroidJUnit4::class)
class LoginUiTest {
@Rule
@JvmField
val composeTestRule = createComposeRule()
@Test
fun login_withValidCredentials_showsWelcome() {
composeTestRule
.onNodeWithTag("emailField")
.performTextInput("user@example.com")
composeTestRule
.onNodeWithTag("passwordField")
.performTextInput("secret123")
composeTestRule
.onNodeWithTag("loginButton")
.performClick()
composeTestRule
.onNodeWithText("Chào mừng, Người dùng!")
.assertIsDisplayed()
}
}
XCUITest sử dụng XCUIApplication để truy cập phần tử giao diện qua định danh trợ năng. Các phương thức tap() và exists cung cấp tương tác và kiểm tra.
class LoginUITests: XCTestCase {
let app = XCUIApplication()
override func setUp() {
continueAfterFailure = false
app.launch()
}
func testLogin_withValidCredentials_showsWelcome() {
app.textFields["emailField"].tap()
app.textFields["emailField"].typeText("user@example.com")
app.secureTextFields["passwordField"].tap()
app.secureTextFields["passwordField"].typeText("secret123")
app.buttons["loginButton"].tap()
XCTAssertTrue(app.staticTexts["Welcome, User!"].exists)
}
}
Nguyên tắc đầu tiên — sử dụng định danh trợ năng thay vì nhãn văn bản để tìm phần tử. Văn bản nút có thể thay đổi khi bản địa hóa, trong khi định danh vẫn ổn định. Trong Android, đây là thuộc tính contentDescription; trong iOS — accessibilityIdentifier. Cách tiếp cận này làm cho kiểm thử độc lập với ngôn ngữ giao diện và giảm chi phí bảo trì khi thay đổi nội dung.
Tránh sleep() và độ trễ cố định — sử dụng cơ chế chờ tích hợp của framework. Espresso tự động chờ hoàn thành hoạt ảnh và tác vụ nền. XCUITest cung cấp XCTAssertTrue với thời gian chờ. Tạm dừng rõ ràng làm cho kiểm thử chậm hơn và không ổn định, đặc biệt trên thiết bị chậm trong môi trường CI.
Nhóm kiểm thử theo mức độ quan trọng: kiểm thử khói (3–5 kịch bản chính) chạy mỗi lần commit, bộ kiểm thử UI đầy đủ chạy trước khi phát hành. Theo Google Testing Blog (2022), kiểm thử UI mất hơn 30 phút trong CI giảm tần suất chạy 40%, làm giảm hiệu quả như công cụ phát hiện hồi quy sớm.
Kiểm thử UI có một số hạn chế. Nhạy cảm với thay đổi bố cục: thay đổi định danh, hệ thống phân cấp hoặc loại phần tử làm hỏng kiểm thử ngay cả khi chức năng không thay đổi. Giải pháp là sử dụng mẫu Page Object, tập trung bộ chọn phần tử trong các lớp riêng biệt. Khi bố cục thay đổi, chỉ một tệp Page Object được sửa, không phải hàng chục kiểm thử.
Thời gian thực thi: chạy trên thiết bị thật hoặc trình giả lập mất nhiều hơn 10–50 lần so với kiểm thử đơn vị. Giải pháp là chạy kiểm thử UI song song trên nhiều thiết bị qua Firebase Test Lab hoặc AWS Device Farm. Sự không ổn định (flakiness) là vấn đề phổ biến trong CI, do hoạt ảnh, độ trễ mạng hoặc trạng thái trình giả lập. Để chống flakiness, sử dụng tự động chạy lại kiểm thử thất bại và phân tích độ ổn định của từng kịch bản kiểm thử.
Câu hỏi thường gặp
Cho một màn hình trung bình, 3–5 kiểm thử UI là đủ: happy path, xác thực lỗi, trạng thái rỗng, thay đổi hướng và kiểm tra trợ năng. Màn hình phức tạp với nhiều trạng thái — biểu mẫu đặt hàng, cài đặt — có thể yêu cầu 10–15 kiểm thử để bao phủ đầy đủ các kịch bản chính.
Có, Appium và Maestro cho phép chạy cùng kịch bản trên cả hai nền tảng. Tuy nhiên, framework gốc — Espresso và XCUITest — cung cấp độ ổn định, tốc độ và truy cập tốt hơn vào các tính năng nền tảng không có sẵn qua proxy WebDriver.
Cho Compose, thư viện Compose UI Test với bộ so khớp ngữ nghĩa được sử dụng: onNodeWithText, onNodeWithTag, onNodeWithContentDescription. Lớp ngữ nghĩa của Compose trừu tượng hóa hệ thống phân cấp view, làm cho kiểm thử ít mong manh hơn so với Espresso truyền thống cho hệ thống View.
Chạy kiểm thử UI cơ bản được thực hiện trên trình giả lập trong CI — nhanh và rẻ. Xác minh cuối cùng trước khi phát hành nên được thực hiện trên thiết bị vật lý qua Firebase Test Lab để tính đến đặc điểm phần cứng thực: độ phân giải khác nhau, phiên bản OS và hiệu suất.
Sử dụng thực thi song song trên nhiều thiết bị, tắt hoạt ảnh trên trình giả lập qua Tùy chọn nhà phát triển, xây dựng kiến trúc kiểm thử mô-đun và chạy bộ khói mỗi lần commit, chạy hồi quy đầy đủ theo lịch hoặc trước khi phát hành.
Tổng kết
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