Kiểm thử snapshot cho ứng dụng di động: cách hoạt động, công cụ và ví dụ

Tác giả: IT Sectr Đã đăng: 2026-04-07 Thời gian đọc: 9 phút

Kiểm thử snapshot là một phương pháp xác minh giao diện người dùng tự động, trong đó trạng thái màn hình hiện tại được so sánh với ảnh tham chiếu (snapshot) được lưu trong lần chạy kiểm thử trước. Bất kỳ sự khác biệt trực quan nào đều được ghi nhận là một thay đổi cần sự xác nhận của nhà phát triển. Không giống như kiểm thử UI kiểm tra sự hiện diện của các phần tử, kiểm thử snapshot phát hiện các thay đổi ở cấp độ pixel — sự dịch chuyển, sai lệch màu sắc và vấn đề về bố cục. Theo Android Developers, 2024, kiểm thử snapshot phát hiện tới 30% các hồi quy trực quan bị bỏ sót bởi kiểm thử UI truyền thống, khiến nó trở thành công cụ không thể thiếu để duy trì giao diện nhất quán.

Những điểm chính

  • Kiểm thử snapshot — phương pháp so sánh kết xuất màn hình hiện tại với ảnh tham chiếu để phát hiện các hồi quy trực quan.
  • Paparazzi — thư viện Android kết xuất các thành phần Compose và View trong môi trường kiểm thử mà không cần chạy trình giả lập.
  • Shot — framework Android chụp ảnh màn hình thực trong kiểm thử Instrumentation với hỗ trợ nhiều độ phân giải.
  • SnapshotTesting — thư viện từ Point-Free cho iOS hỗ trợ so sánh không chỉ ảnh mà còn văn bản, JSON và dữ liệu Core Data.
  • Cập nhật tham chiếu — lệnh một lần sau khi thay đổi giao diện có chủ ý, thay thế snapshot cũ bằng snapshot mới.

Kiểm thử snapshot là gì?

Kiểm thử snapshot là một kỹ thuật trong đó kiểm thử kết xuất một thành phần giao diện, lưu ảnh kết quả làm tham chiếu và trong các lần chạy sau đó so sánh kết xuất hiện tại với tham chiếu này. Nếu ảnh khớp — kiểm thử đạt. Nếu tìm thấy sự khác biệt — kiểm thử thất bại và nhà phát triển nhận được ảnh diff với các pixel thay đổi được đánh dấu. Kỹ thuật này được mượn từ phát triển web (Jest snapshot) và được điều chỉnh cho các nền tảng di động.

Giá trị chính của kiểm thử snapshot là tự động phát hiện các thay đổi trực quan không mong đợi. Một nhà phát triển có thể thay đổi bảng màu trong chủ đề toàn cục và vô tình ảnh hưởng đến hàng chục màn hình. Các kiểm thử UI kiểm tra sự hiện diện của nút và văn bản sẽ không nhận thấy điều này. Một kiểm thử snapshot sẽ ghi lại mọi thay đổi pixel trên mọi màn hình bị ảnh hưởng, cung cấp bức tranh toàn cảnh về tác động của thay đổi.

Theo khảo sát của Mobile DevOps Summit 2023, các nhóm sử dụng kiểm thử snapshot bổ sung cho kiểm thử UI cổ điển giảm 40% số lượng lỗi trực quan trong các bản phát hành. Cách tiếp cận này đặc biệt hiệu quả trong các dự án có hệ thống thiết kế và kiến trúc dựa trên thành phần, nơi việc thay đổi một thành phần cơ sở có thể ảnh hưởng đến hàng chục màn hình ứng dụng.

Sự khác biệt giữa kiểm thử snapshot và kiểm thử UI

Sự khác biệt cơ bản nằm ở đối tượng xác minh. Kiểm thử UI kiểm tra sự hiện diện, trạng thái và hành vi của các phần tử giao diện: “nút có hiển thị”, “văn bản chứa thông báo lỗi”, “sau khi nhấn sẽ mở màn hình mới”. Kiểm thử snapshot kiểm tra toàn bộ diện mạo trực quan: vị trí phần tử, lề, màu sắc, phông chữ, bóng và góc bo tròn. Kiểm thử snapshot trả lời câu hỏi “màn hình có trông như mong đợi không?”, trong khi kiểm thử UI trả lời “màn hình có hoạt động như mong đợi không?”

Tốc độ thực thi cũng khác nhau. Kiểm thử UI chạy trên trình giả lập hoặc thiết bị thật, yêu cầu tải toàn bộ ứng dụng và mất từ 10 giây đến một phút cho mỗi kịch bản. Kiểm thử snapshot sử dụng các thư viện như Paparazzi kết xuất thành phần trong môi trường ảo mà không cần chạy trình giả lập, giảm thời gian kiểm thử xuống còn 100–500 mili giây. Một bộ kiểm thử snapshot đầy đủ (50–100 màn hình) được thực thi trong 2–5 phút thay vì 30–60 phút cho một bộ kiểm thử UI tương đương.

Tuy nhiên, kiểm thử snapshot không thay thế kiểm thử UI. Chiến lược tối ưu là sự kết hợp: kiểm thử snapshot bao phủ hồi quy trực quan (kết xuất từng màn hình ở trạng thái cơ bản), trong khi kiểm thử UI bao phủ các khía cạnh hành vi (kịch bản nhấp chuột, xác thực đầu vào, điều hướng). Sự kết hợp này mang lại 90% độ tin cậy về tính chính xác của giao diện với thời gian chạy CI tối thiểu.

Công cụ kiểm thử snapshot

Trên Android, các công cụ chính là Paparazzi và Shot. Paparazzi từ Cash App kết xuất các thành phần trong môi trường kiểm thử JVM mà không cần trình giả lập, sử dụng bố cục trọng lực Layoutlib. Shot từ Karumi chụp ảnh màn hình Instrumentation trên thiết bị thật hoặc trình giả lập và so sánh chúng với các tham chiếu qua thư viện AShot, có tính đến sự khác biệt về độ phân giải và mật độ pixel.

Paparazzi cho Android

Paparazzi không yêu cầu chạy trình giả lập — việc kết xuất được thực hiện trên JVM thông qua Layoutlib, mang lại tốc độ tương đương với kiểm thử đơn vị. Thư viện hỗ trợ cả hệ thống View và Jetpack Compose. Đối với Compose, sử dụng bổ tố paparazzi.snapshot { MyComposable() }. Các tham chiếu được lưu trữ trong src/test/snapshots và tự động được so sánh ở mỗi lần chạy. Tỷ lệ chênh lệch tối đa có thể cấu hình qua maxPercentDifference.

SnapshotTesting cho iOS

SnapshotTesting từ Point-Free hỗ trợ so sánh không chỉ UIImage mà còn chuỗi, JSON, Data và toàn bộ kho lưu trữ Core Data. Điều này làm cho nó trở thành công cụ đa năng không chỉ cho snapshot UI mà còn để xác minh tuần tự hóa và giải mã các phản hồi JSON. Đối với SwiftUI, sử dụng phần mở rộng assertSnapshot với bổ tố .image(on: .iPhone13). Chiến lược record: true tạo tham chiếu ở lần chạy đầu tiên.

Cách tiếp cận đa nền tảng

Đối với React Native, giải pháp phổ biến là react-native-testing-library kết hợp với jest-image-snapshot. Cách tiếp cận web đối với kiểm thử snapshot được chuyển sang môi trường di động bằng cách kết xuất các thành phần trong môi trường Node.js, sau đó so sánh các snapshot JSON của DOM ảo. Cách tiếp cận này nhanh hơn native nhưng kém chính xác hơn — nó không tính đến các đặc điểm kết xuất phông chữ và thành phần hệ thống dành riêng cho từng nền tảng. Đối với Flutter, kiểm thử golden được sử dụng thông qua bộ công cụ goldens.

Ví dụ mã cho kiểm thử snapshot

Hãy xem xét kiểm thử snapshot cho Android (Paparazzi) và iOS (SnapshotTesting). Cả hai ví dụ đều xác minh diện mạo của một thành phần — thẻ người dùng có hình đại diện, tên và trạng thái. Kiểm thử kết xuất thành phần với dữ liệu kiểm thử và so sánh kết quả với ảnh tham chiếu được lưu trong kho lưu trữ.

Android: kiểm thử snapshot với Paparazzi

Paparazzi sử dụng chú thích @Test và phương thức snapshot() để ghi lại kết xuất. Các tham chiếu được lưu trong thư mục src/test/snapshots và tự động tải vào lần chạy tiếp theo để so sánh.

kotlin
class UserCardSnapshotTest {

    @get:Rule
    val paparazzi = Paparazzi(
        theme = "Theme.MyApp",
        maxPercentDifference = 0.1
    )

    @Test
    fun userCard_defaultState() {
        val card = UserCard(
            name = "Alice Johnson",
            status = "Online",
            avatarUrl = "https://example.com/avatar.png"
        )
        paparazzi.snapshot(card)
    }

    @Test
    fun userCard_offlineState() {
        val card = UserCard(
            name = "Bob Smith",
            status = "Offline",
            avatarUrl = null
        )
        paparazzi.snapshot(card, name = "user_card_offline")
    }
}

iOS: kiểm thử snapshot với SnapshotTesting

SnapshotTesting sử dụng bổ tố .snapshot() bên trong assertSnapshot. Thư viện tự động xác định định dạng — UIImage cho UIView, String cho văn bản, Data cho dữ liệu nhị phân.

swift
import SnapshotTesting
import XCTest

class UserCardSnapshotTests: XCTestCase {
    func testUserCardDefaultState() {
        let card = UserCardView(
            name: "Alice Johnson",
            status: "Online",
            avatarURL: URL(string: "https://example.com/avatar.png")
        )
        let controller = UIHostingController(rootView: card)
        assertSnapshot(matching: controller, as: .image(on: .iPhone13))
    }

    func testUserCardOfflineState() {
        let card = UserCardView(
            name: "Bob Smith",
            status: "Offline",
            avatarURL: nil
        )
        assertSnapshot(matching: card, as: .image(on: .iPhone13))
    }
}

Quy trình kiểm thử snapshot

Quy trình làm việc điển hình bao gồm bốn giai đoạn. Lần chạy đầu tiên (chế độ ghi): tất cả các kiểm thử snapshot được thực thi ở chế độ ghi — ảnh tham chiếu được tạo và lưu vào kho lưu trữ. Giai đoạn này được thực hiện trong quá trình thiết lập kiểm thử ban đầu hoặc sau khi thay đổi giao diện có chủ ý. Sau khi ghi, các tham chiếu được commit cùng với mã — chúng trở thành một phần của dự án.

Trong các lần chạy tiếp theo, các kiểm thử hoạt động ở chế độ so sánh: mỗi kết xuất mới được so sánh với tham chiếu. Nếu tìm thấy sự khác biệt, ảnh diff được tạo ra: pixel khớp với tham chiếu được đánh dấu màu xanh lá cây, pixel khác biệt được đánh dấu màu đỏ. Nhà phát triển nghiên cứu diff và đưa ra quyết định: nếu thay đổi được mong đợi (thay đổi thiết kế có chủ ý), tham chiếu được cập nhật bằng lệnh ghi; nếu không mong đợi — lỗi được sửa. Cập nhật tham chiếu được thực hiện bằng một lệnh duy nhất: đối với Paparazzi là `./gradlew recordPaparazzi`, đối với SnapshotTesting — `assertSnapshot(record: true)`.

Theo Spotify Engineering Blog (2022), các nhóm sử dụng quy trình làm việc được mô tả dành trung bình 2 phút cho mỗi kiểm thử để phân tích ảnh diff. Với bộ 50 kiểm thử snapshot, một chu kỳ cập nhật tham chiếu đầy đủ mất 15–20 phút, nhanh hơn đáng kể so với việc xác minh thủ công các thay đổi trực quan trên 50 màn hình.

Hạn chế và phản mẫu của kiểm thử snapshot

Kiểm thử snapshot có những hạn chế cơ bản. Nhạy cảm với môi trường: cùng một thành phần có thể được kết xuất khác nhau trên các phiên bản HĐH, mật độ màn hình và cấu hình phông chữ khác nhau. Các tham chiếu được tạo trên một máy có thể khác với kết xuất trên máy chủ CI. Giải pháp là sử dụng các tham số môi trường cố định: phiên bản Layoutlib cụ thể cho Paparazzi hoặc mẫu thiết bị chính xác cho SnapshotTesting.

Phản mẫu số 1: snapshot khổng lồ — kiểm thử snapshot chụp toàn bộ màn hình sẽ thất bại với mọi thay đổi nhỏ nhất trên bất kỳ thành phần nào. Cách tiếp cận đúng là kiểm thử các thành phần riêng lẻ (nút, thẻ, trường nhập liệu) một cách riêng biệt. Mỗi thành phần được kiểm thử độc lập, cho phép xác định chính xác nguồn gốc của thay đổi. Phản mẫu số 2: bỏ qua diff — tự động cập nhật tham chiếu mà không phân tích ảnh diff làm giảm giá trị của kiểm thử snapshot xuống bằng không. Mỗi diff đòi hỏi quyết định có ý thức của nhà phát triển.

Theo Better Engineering Blog (2023), kiểm thử snapshot mang lại giá trị lớn nhất khi bao phủ các thành phần của hệ thống thiết kế và các màn hình chính ở trạng thái cơ bản — trống, đã điền, lỗi và ranh giới. Bao phủ hoạt ảnh và trạng thái động thông qua kiểm thử snapshot không hiệu quả do tính chất không xác định của dấu thời gian trong kết xuất — đối với các kịch bản như vậy, ghi hình video hoặc kiểm tra QA thủ công phù hợp hơn.

Câu hỏi thường gặp

Kiểm thử snapshot có thay thế kiểm thử UI không?

Không, kiểm thử snapshot kiểm tra diện mạo trực quan, trong khi kiểm thử UI kiểm tra hành vi giao diện. Chiến lược tối ưu là kết hợp cả hai cách tiếp cận: snapshot cho hồi quy trực quan, kiểm thử UI cho các kịch bản và điều hướng. Snapshot trả lời “có trông đúng không”, kiểm thử UI trả lời “có hoạt động đúng không”.

Bao lâu nên cập nhật ảnh tham chiếu một lần?

Các tham chiếu được cập nhật với mọi thay đổi thiết kế có chủ ý: màu chủ đề mới, lề được sửa đổi, thêm hoặc xóa phần tử. Cập nhật được thực hiện thông qua chế độ ghi, sau đó ảnh diff được xem xét trong quá trình đánh giá mã để đảm bảo các thay đổi phù hợp với mong đợi của nhà thiết kế.

Những thành phần nào nên được bao phủ bằng kiểm thử snapshot?

Đầu tiên và quan trọng nhất, các thành phần của hệ thống thiết kế — nút, thẻ, trường nhập liệu, cửa sổ phương thức. Sau đó là các màn hình chính ở trạng thái cơ bản. Không kiểm thử bằng snapshot hoạt ảnh, WebView, bản đồ và màn hình có nội dung động — snapshot tạo ra lỗi sai do tính không xác định.

Làm thế nào để xử lý lỗi sai do các phiên bản HĐH khác nhau?

Sử dụng cùng một cấp độ API cho cả chế độ ghi và kiểm thử. Đối với Paparazzi, chỉ định phiên bản Layoutlib cụ thể trong cấu hình. Đối với SnapshotTesting, cố định mẫu thiết bị. Các tham chiếu được tạo trên Android 14 có thể khác với kết xuất trên Android 12 do thay đổi trong phông chữ hệ thống và chủ đề Material.

Kiểm thử snapshot trong CI — làm thế nào để cấu hình?

Trong CI, kiểm thử snapshot chạy ở chế độ xác minh (verify). Nếu kiểm thử thất bại, CI hiển thị ảnh diff trong các tạo phẩm xây dựng. Chế độ ghi (cập nhật tham chiếu) được thực hiện cục bộ bởi nhà phát triển hoặc trong một tác vụ CI riêng với kích hoạt thủ công. Ảnh tham chiếu phải được commit vào kho lưu trữ.

Tổng kết

  • Kiểm thử snapshot so sánh kết xuất thành phần hiện tại với ảnh tham chiếu, phát hiện thay đổi pixel và hồi quy trực quan.
  • Paparazzi — công cụ nhanh cho Android không cần trình giả lập; SnapshotTesting — thư viện đa năng cho iOS từ Point-Free.
  • Kiểm thử snapshot không thay thế kiểm thử UI — chúng bổ sung cho nhau: snapshot cho trực quan, kiểm thử UI cho hành vi.
  • Chế độ ghi tạo ảnh tham chiếu; chế độ xác minh so sánh kết xuất hiện tại với chúng và tạo diff khi có khác biệt.
  • Các thành phần hệ thống thiết kế là mục tiêu ưu tiên cho kiểm thử snapshot, vì thay đổi của chúng ảnh hưởng đến nhiều màn hình.
  • Mỗi diff đòi hỏi quyết định có ý thức của nhà phát triển — tự động thay thế tham chiếu mà không phân tích làm mất giá trị của kiểm thử.
  • Ảnh tham chiếu được commit vào kho lưu trữ và là một phần của cơ sở mã cùng với mã nguồn kiểm thử.

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.

Thảo luận dự án

Đọc thêm