Mở đầu — vì sao bài này quan trọng
Hãy tưởng tượng bạn vừa test một tính năng thanh toán trên website, mọi thứ chạy hoàn hảo trên máy tính của bạn. Nhưng khi ứng dụng lên tay người dùng thật, bạn nhận về hàng loạt báo lỗi: nút "Đặt hàng" bị màn hình che mất trên một dòng máy Samsung, app crash trên Android 8, chữ tiếng Việt bị tràn ra ngoài khung trên iPhone SE màn hình nhỏ. Đó chính là thế giới của mobile testing — nơi mà "chạy tốt trên máy của tôi" gần như vô nghĩa.
Ở Việt Nam và Đông Nam Á nói chung, di động là màn hình chính. Theo các báo cáo thị trường, hơn 70% lưu lượng truy cập thương mại điện tử tại Việt Nam đến từ điện thoại, và phần lớn người dùng đang cầm những chiếc Android tầm trung, tầm thấp — Samsung Galaxy A-series, Oppo, Xiaomi Redmi, Vivo. Nếu app của bạn chỉ được test trên chiếc iPhone đời mới của trưởng nhóm, bạn đang bỏ mù phần lớn khách hàng thật.
Bài học này trang bị cho bạn nền tảng để hiểu vì sao kiểm thử di động khác biệt căn bản so với kiểm thử web/desktop, những chiều rủi ro đặc thù của iOS và Android, và cách xây dựng một chiến lược test di động thực tế mà không cần một tủ đầy hàng trăm chiếc điện thoại. Đây là kỹ năng bắt buộc với bất kỳ tester nào làm sản phẩm hướng đến người dùng cuối tại thị trường của chúng ta.
Khái niệm cốt lõi
Vì sao mobile testing khác web testing
Trên web, bạn kiểm soát được khá nhiều thứ: một vài trình duyệt phổ biến, độ phân giải màn hình trong khoảng hợp lý, môi trường mạng thường ổn định. Trên di động, gần như mọi biến số đều nhân lên nhiều lần và nằm ngoài tầm kiểm soát của bạn. Có bốn nhóm khác biệt lớn cần nắm.
1. Sự đa dạng thiết bị (device diversity). Thị trường Android có hàng ngàn model đang hoạt động, từ những chiếc flagship giá 25 triệu đến điện thoại phổ thông 2 triệu đồng. Mỗi hãng — Samsung, Xiaomi, Oppo, Vivo, Realme — lại tùy biến giao diện riêng (One UI, MIUI/HyperOS, ColorOS, Funtouch OS), thay đổi cách hiển thị thông báo, quyền, phím back, khiến cùng một app hành xử khác nhau. iOS thì đồng nhất hơn nhiều nhưng vẫn có nhiều kích thước màn hình và đời máy khác nhau.
2. Phân mảnh hệ điều hành (OS fragmentation). Người dùng không cập nhật đồng loạt. Ngay lúc này bạn vẫn có người chạy Android 9, người chạy Android 14, và số nhỏ vẫn ở Android 8 hoặc cũ hơn. Mỗi phiên bản OS thay đổi mô hình quyền (permission), cách xử lý nền (background), API khả dụng. Với iOS tỉ lệ nâng cấp cao hơn, nhưng bạn vẫn phải hỗ trợ ít nhất hai đến ba phiên bản iOS gần nhất.
3. Điều kiện mạng biến động. Người dùng web thường ngồi cạnh WiFi ổn định. Người dùng di động chuyển liên tục giữa 5G, 4G, 3G, WiFi công cộng chập chờn, và cả những khoảng mất sóng hoàn toàn khi vào thang máy, hầm gửi xe, hoặc đi tàu. App phải xử lý được việc mất kết nối giữa chừng một giao dịch.
4. Đặc thù của chính thiết bị. Điện thoại có pin, có cảm biến, có cuộc gọi đến làm gián đoạn, có thông báo đè lên màn hình, có xoay ngang/dọc, có bàn phím ảo che nội dung, có cử chỉ vuốt. Đây là những "interruption" (gián đoạn) mà web hầu như không có.
Native, Web app và Hybrid
Bạn cần phân biệt ba loại ứng dụng vì cách test khác nhau. Native app viết bằng ngôn ngữ gốc của nền tảng (Swift/Kotlin), cài từ App Store/Google Play, dùng API hệ thống trực tiếp — hiệu năng cao nhất, cần test kỹ nhất về tương thích thiết bị. Mobile web app chạy trong trình duyệt điện thoại, thực chất là kiểm thử responsive web. Hybrid app đóng gói web bên trong một vỏ native (như React Native, Flutter, Ionic) — bạn phải test cả phần giao diện web bên trong lẫn các cầu nối tới tính năng native như camera, GPS, thông báo đẩy.
Các loại kiểm thử đặc thù di động
Ngoài kiểm thử chức năng thông thường, mobile có vài loại test rất riêng mà bạn phải chủ động nghĩ tới:
- Installation/Update testing: cài mới, cập nhật từ phiên bản cũ, gỡ cài đặt có xóa sạch dữ liệu không, dữ liệu cũ có tương thích sau update không.
- Interruption testing: cuộc gọi đến, tin nhắn, báo thức, thông báo app khác, cắm/rút sạc, pin yếu — xem app có mất dữ liệu đang nhập không.
- Permission testing: người dùng từ chối quyền camera/vị trí/thông báo thì app xử lý ra sao, có crash không, có hướng dẫn lại không.
- Battery & performance: app có ngốn pin, làm nóng máy, chiếm RAM quá mức không.
- Gesture & orientation: vuốt, chạm giữ, xoay màn hình, bàn phím ảo che ô nhập liệu.
Thiết bị thật vs Giả lập vs Cloud
Bạn có ba lựa chọn môi trường test. Emulator/Simulator (giả lập trên máy tính) nhanh, miễn phí, tốt cho kiểm thử sớm nhưng không phản ánh đúng hiệu năng thật, cảm biến thật, hay quirk của từng hãng. Thiết bị thật cho kết quả đáng tin nhất nhưng tốn kém và khó phủ hết. Cloud device farm (như BrowserStack, Sauce Labs, AWS Device Farm, Firebase Test Lab) cho bạn thuê hàng trăm thiết bị thật qua trình duyệt — giải pháp thực tế cho đội nhỏ ở Việt Nam không đủ ngân sách mua thiết bị.
Tình huống thực tế
Tình huống 1 — Nút đặt hàng "biến mất" trên máy giá rẻ
Một startup giao đồ ăn tại TP.HCM (gọi là "FoodNow") test app rất kỹ trên iPhone 14 và Samsung Galaxy S23 của team. Ra mắt được hai tuần, tỷ lệ hoàn tất đơn hàng thấp bất thường ở nhóm người dùng Android. Đội QA vào cuộc, thuê thiết bị trên cloud device farm và tái hiện được vấn đề: trên các máy màn hình nhỏ như Samsung Galaxy A03 và Redmi 9A (rất phổ biến ở phân khúc bình dân, độ phân giải thấp), nút "Xác nhận đặt hàng" bị đẩy xuống dưới vùng an toàn màn hình và bị thanh điều hướng của hệ thống che mất một nửa. Người dùng không bấm được, và họ bỏ giỏ hàng.
Diễn giải: bug này không phải lỗi logic, mà là lỗi bố cục trên màn hình nhỏ với mật độ điểm ảnh thấp — thứ team không bao giờ thấy vì họ chỉ dùng máy cao cấp. Bài học rút ra: ma trận thiết bị test phải phản ánh thiết bị của người dùng thật, không phải thiết bị của đội phát triển. FoodNow sau đó thêm hai máy Android tầm thấp phổ biến vào bộ test bắt buộc, và luôn kiểm tra vùng safe area cùng nút hành động chính trên màn hình nhỏ nhất mà họ hỗ trợ.
Tình huống 2 — Ví điện tử mất kết nối giữa giao dịch
Một đội QA làm việc cho một ví điện tử tương tự MoMo test tính năng chuyển tiền. Trên WiFi phòng lab mọi thứ mượt mà. Nhưng một tester quyết định thử kịch bản thực tế: bắt đầu chuyển 500.000đ, rồi bật chế độ máy bay ngay khi màn hình đang quay vòng loading "Đang xử lý". Khi bật mạng lại, app hiển thị "Giao dịch thất bại" — nhưng phía server thực ra đã trừ tiền thành công. Người dùng vừa mất tiền vừa tưởng chưa chuyển, và có thể chuyển lại lần hai.
Diễn giải: đây là lỗi kinh điển của interruption testing kết hợp với xử lý mạng yếu. App không có cơ chế đối soát lại trạng thái giao dịch (idempotency và reconciliation) khi mạng phục hồi. Với người Việt hay đi thang máy, hầm xe, vùng sóng yếu, kịch bản này xảy ra thường xuyên. Bài học: với luồng liên quan tiền bạc, tester bắt buộc phải test mất mạng ngay giữa giao dịch, chứ không chỉ test lúc khởi đầu. Đội này sau đó đưa "ngắt mạng giữa transaction" thành test case bắt buộc cho mọi luồng thanh toán.
Tình huống 3 — App crash sau khi cập nhật OS
Một công ty e-learning có app học tiếng Anh chạy ổn định nhiều tháng. Rồi Apple phát hành iOS mới, và trong vòng vài ngày lượng crash tăng vọt, đánh giá 1 sao đổ về ào ạt. Nguyên nhân: một API mà app dùng để lưu tiến độ học đã bị thay đổi hành vi ở phiên bản iOS mới, khiến app crash khi mở bài học. Vì đội không test trên bản beta của iOS trước khi Apple phát hành chính thức, họ bị động hoàn toàn.
Diễn giải: OS fragmentation không chỉ là chuyện phiên bản cũ, mà cả phiên bản mới sắp ra. Apple và Google đều phát hành bản beta cho lập trình viên trước nhiều tuần. Bài học: đội QA nên đưa việc test trên bản beta OS sắp phát hành vào lịch, đặc biệt trước mùa Apple ra iOS mới hằng năm (tháng 9). Chủ động test sớm rẻ hơn nhiều so với chữa cháy khi đã có hàng ngàn đánh giá 1 sao.
Hướng dẫn từng bước
Đây là quy trình thực tế để bạn bắt đầu một chu kỳ kiểm thử di động.
Bước 1 — Xây ma trận thiết bị dựa trên dữ liệu người dùng thật. Đừng đoán. Lấy số liệu từ Google Analytics, Firebase, hoặc báo cáo phân tích của app để biết người dùng của BẠN đang dùng model nào, OS nào, độ phân giải nào. Sắp xếp theo thị phần rồi chọn phủ khoảng 80% người dùng bằng số lượng thiết bị hợp lý. Một ma trận điển hình cho thị trường Việt Nam nên có: một iPhone đời mới, một iPhone màn hình nhỏ/đời cũ hơn, một Samsung tầm trung, một Xiaomi/Oppo tầm thấp, phủ khoảng ba phiên bản OS gần nhất mỗi nền tảng.
Bước 2 — Phân loại app và xác định vùng rủi ro. Xác định app là native, web hay hybrid. Với hybrid, đánh dấu rõ các điểm giao tiếp native (camera, GPS, thanh toán, push) vì đó là nơi dễ vỡ nhất.
Bước 3 — Viết test case bao gồm cả kịch bản đặc thù di động. Bên cạnh chức năng, thêm hẳn các mục: cài đặt/cập nhật, gián đoạn (cuộc gọi, thông báo), quyền (cho/từ chối), mạng (4G, WiFi yếu, mất mạng, chuyển mạng), xoay màn hình, bàn phím ảo che nội dung, và hiển thị trên màn hình nhỏ nhất.
Bước 4 — Test trên giả lập trước để bắt lỗi sớm và rẻ. Dùng emulator/simulator cho vòng kiểm thử đầu, phát hiện lỗi rõ ràng về chức năng và bố cục trước khi đụng thiết bị thật.
Bước 5 — Xác nhận trên thiết bị thật hoặc cloud. Những gì liên quan đến hiệu năng, cảm biến, cử chỉ, pin, camera và trải nghiệm thật bắt buộc phải kiểm trên máy thật hoặc cloud device farm. Ưu tiên thiết bị tầm thấp phổ biến vì đó là nơi lỗi hiệu năng lộ ra.
Bước 6 — Kiểm thử mạng có chủ đích. Dùng công cụ giả lập mạng (network throttling trong công cụ dev, hoặc bật chế độ máy bay đúng thời điểm) để test hành vi khi mạng chậm và khi mất kết nối giữa chừng.
Bước 7 — Ghi lại bug với đầy đủ ngữ cảnh thiết bị. Mỗi báo cáo lỗi di động phải kèm: tên model, phiên bản OS, phiên bản app, điều kiện mạng, và tốt nhất là video quay lại. Thiếu ngữ cảnh này, lập trình viên gần như không tái hiện được.
Lỗi thường gặp & mẹo
Lỗi: chỉ test trên thiết bị cao cấp của đội. Đây là cái bẫy số một. Máy của bạn màn hình đẹp, RAM lớn, mạng khỏe — hoàn toàn không giống chiếc Android tầm thấp của phần lớn khách hàng. Mẹo: luôn có ít nhất một thiết bị "yếu" phổ biến trong bộ test bắt buộc.
Lỗi: quên test kịch bản cập nhật app. Nhiều đội chỉ cài mới sạch sẽ rồi test. Nhưng người dùng thật là nâng cấp từ bản cũ. Mẹo: luôn test luồng update từ phiên bản trước đó lên phiên bản mới, xem dữ liệu cũ có còn nguyên và tương thích không.
Lỗi: bỏ qua interruption. Cuộc gọi đến giữa lúc đang nhập form dài, app khởi động lại và mất hết dữ liệu — người dùng cực kỳ khó chịu. Mẹo: với mọi form quan trọng, test kịch bản bị gián đoạn rồi quay lại.
Lỗi: không test khi từ chối quyền. Tester hay bấm "Cho phép" theo phản xạ. Nhưng nhiều người dùng từ chối quyền vì lo ngại quyền riêng tư. Mẹo: luôn test cả nhánh "Từ chối" cho camera, vị trí, thông báo, và xem app có xử lý mượt không.
Lỗi: báo bug thiếu thông tin thiết bị. "App bị crash" mà không nói máy gì, OS nào thì vô dụng. Mẹo: chuẩn hóa template báo lỗi di động với các trường bắt buộc về thiết bị và mạng.
Mẹo về bàn phím ảo: một lỗi hay bị bỏ sót là bàn phím ảo bật lên che mất nút submit hoặc ô nhập bên dưới. Luôn test các form dài với bàn phím đang mở.
Mẹo về tiếng Việt trên màn hình nhỏ: chữ tiếng Việt có dấu thường dài hơn tiếng Anh và có ký tự cao (dấu mũ, dấu nặng) dễ bị cắt. Luôn kiểm tra nhãn, nút, tiêu đề bằng tiếng Việt trên màn hình nhỏ nhất bạn hỗ trợ.
Bài tập thực hành
Bài 1 — Xây ma trận thiết bị. Giả sử bạn phụ trách QA cho một app thương mại điện tử phục vụ người dùng Việt Nam. Hãy lập một ma trận thiết bị gồm tối đa 6 thiết bị (kết hợp model + phiên bản OS) sao cho phủ được cả iOS lẫn Android, cả máy cao cấp lẫn tầm thấp, và cả màn hình nhỏ lẫn lớn. Ghi rõ lý do chọn từng thiết bị.
Bài 2 — Viết test case interruption. Chọn một luồng quan trọng (ví dụ: đăng ký tài khoản với form nhiều bước). Viết ít nhất 4 test case về gián đoạn: cuộc gọi đến, thông báo đè lên, xoay màn hình giữa chừng, và bật/tắt máy bay. Với mỗi case, ghi rõ kết quả mong đợi.
Bài 3 — Kịch bản mạng. Viết test case cho một luồng thanh toán mô phỏng theo tình huống ví điện tử ở trên. Liệt kê ít nhất 3 thời điểm ngắt mạng khác nhau trong luồng và kết quả mong đợi tương ứng cho mỗi thời điểm, chú trọng việc không được để người dùng mất tiền hoặc bị trừ tiền hai lần.
Bài 4 — Rà soát báo cáo lỗi. Cho một bug report chỉ ghi "App treo khi mở giỏ hàng". Hãy viết lại thành một báo cáo lỗi di động chuẩn với đầy đủ các trường ngữ cảnh cần thiết (thiết bị, OS, phiên bản app, mạng, các bước tái hiện).
Tóm tắt
Kiểm thử di động khác căn bản so với kiểm thử web vì bốn chiều biến động: sự đa dạng thiết bị (đặc biệt hàng ngàn model Android), phân mảnh hệ điều hành (cả bản cũ lẫn bản beta sắp ra), điều kiện mạng thay đổi liên tục, và các đặc thù của chính thiết bị như gián đoạn, quyền, cảm biến, bàn phím ảo. Bạn cần phân biệt native, web và hybrid app vì cách test khác nhau, và cân nhắc ba môi trường: giả lập rẻ và nhanh, thiết bị thật đáng tin, cloud device farm là giải pháp thực tế cho đội nhỏ.
Nguyên tắc quan trọng nhất rút ra từ ba tình huống thực tế: hãy test bằng thiết bị và điều kiện của người dùng thật, không phải của đội phát triển. Nút đặt hàng biến mất trên máy giá rẻ, giao dịch mất tiền khi ngắt mạng giữa chừng, app crash sau khi OS cập nhật — tất cả đều bắt nguồn từ việc bỏ qua thực tế của người dùng cuối. Xây ma trận thiết bị dựa trên dữ liệu thật, chủ động test các kịch bản đặc thù di động, và luôn ghi lại bug kèm đầy đủ ngữ cảnh thiết bị. Đó là nền tảng để bạn trở thành một tester di động vững vàng.