Mở đầu — vì sao bài này quan trọng
Nếu bạn từng nghe một QA nói "test xong trên Android rồi, iOS thì y hệt thôi" — thì đó chính là câu nói đắt giá nhất trong sự nghiệp của họ. Bởi vì iOS và Android không phải là hai phiên bản của cùng một thứ. Chúng là hai thế giới riêng biệt: khác hệ điều hành, khác ngôn ngữ thiết kế, khác cách phân phối ứng dụng, khác cách người dùng tương tác, và quan trọng nhất với chúng ta — khác cách app có thể hỏng.
Trong Bài 1, bạn đã có cái nhìn tổng quan về mobile testing. Bài này đi sâu vào một câu hỏi nền tảng mà mọi Mobile QA đều phải trả lời được: hai nền tảng này khác nhau ở đâu, và những khác biệt đó tạo ra rủi ro chất lượng gì? Đây không phải kiến thức lý thuyết suông. Mỗi khác biệt về nền tảng đều dịch trực tiếp thành test case bạn phải viết, thành bug bạn phải săn, thành thiết bị bạn phải mua.
Với thị trường Việt Nam, câu chuyện càng thú vị. Android chiếm khoảng 70-75% thị phần, nhưng nhóm người dùng iPhone lại thường là phân khúc chi tiêu cao — nên với các app thương mại điện tử, ví điện tử, hay ngân hàng số, iOS tuy ít máy hơn nhưng lại đóng góp doanh thu lớn. Bỏ sót một bug thanh toán trên iOS có thể còn tốn kém hơn cả trên Android. Vì vậy, hiểu sâu cả hai nền tảng không phải là "nice to have" — nó là năng lực cốt lõi.
Khái niệm cốt lõi
Hai ecosystem, hai triết lý
Điểm khác biệt gốc rễ nằm ở triết lý. Apple kiểm soát toàn bộ chuỗi: họ làm cả phần cứng (iPhone, iPad), hệ điều hành (iOS), lẫn cửa hàng phân phối (App Store). Kết quả là số lượng thiết bị và phiên bản OS mà bạn phải test tương đối hữu hạn và dễ đoán.
Google thì ngược lại: Android là mã nguồn mở, và hàng chục hãng (Samsung, Xiaomi, OPPO, Vivo, Realme...) tùy biến nó theo ý mình. Điều này tạo ra hiện tượng nổi tiếng gọi là fragmentation (phân mảnh) — hàng nghìn model máy, hàng chục lớp giao diện tùy biến (Samsung One UI, Xiaomi MIUI/HyperOS, OPPO ColorOS...), chạy trên nhiều phiên bản OS khác nhau cùng lúc. Với QA, fragmentation là kẻ thù số một trên Android.
Phiên bản OS và tốc độ cập nhật
Đây là khác biệt cực kỳ quan trọng khi lên ma trận test.
Trên iOS, người dùng nâng cấp OS rất nhanh. Chỉ sau vài tháng ra mắt, phiên bản iOS mới nhất thường đã chiếm 70-80% thiết bị đang hoạt động. Nghĩa là bạn thường chỉ cần test 2-3 phiên bản iOS gần nhất là phủ được phần lớn người dùng.
Trên Android, tình hình bi đát hơn nhiều. Do các hãng và nhà mạng phải tự đẩy bản cập nhật, một chiếc máy giá rẻ có thể mắc kẹt ở phiên bản OS cũ suốt vòng đời của nó. Trong một ứng dụng Việt Nam điển hình, bạn có thể thấy người dùng trải dài từ Android 9 (2018) đến Android 15 — tức là bạn phải hỗ trợ và test một khoảng phiên bản rộng gấp đôi, ba lần so với iOS.
Ngôn ngữ thiết kế: Human Interface Guidelines vs Material Design
Apple có Human Interface Guidelines (HIG), Google có Material Design. Đây không chỉ là chuyện thẩm mỹ — chúng quy định cách các thành phần UI hành xử, và QA phải kiểm tra app tuân thủ đúng quy ước của từng nền tảng:
- Nút Back (quay lại): iOS không có nút back cứng; người dùng dùng nút "< Back" ở góc trên trái hoặc vuốt từ mép trái màn hình. Android truyền thống có nút back của hệ thống (nay là cử chỉ vuốt từ mép). Đây là nguồn bug kinh điển: một màn hình được thiết kế đúng cho iOS có thể "kẹt" điều hướng trên Android nếu dev không xử lý nút back hệ thống.
- Navigation & tab bar: iOS thường đặt thanh tab ở dưới đáy; Android trước đây hay dùng menu hamburger và app bar ở trên. Vị trí, hành vi các phần tử này khác nhau.
- Ngày giờ, picker, share sheet: Trình chọn ngày (date picker), hộp chọn (dropdown), và menu chia sẻ (share) trông và hoạt động khác nhau hoàn toàn giữa hai OS.
- Font hệ thống: iOS dùng San Francisco, Android dùng Roboto. Cùng một đoạn text tiếng Việt có dấu có thể chiếm chiều rộng khác nhau, dẫn tới lỗi tràn chữ (text overflow) hoặc cắt chữ (truncation) chỉ xuất hiện trên một nền tảng.
Phân quyền (permissions) và vòng đời ứng dụng
Cách hai OS xin quyền truy cập (camera, vị trí, thông báo, danh bạ...) khác nhau về cả thời điểm lẫn cách người dùng thu hồi. iOS nổi tiếng nghiêm ngặt về quyền riêng tư (ví dụ App Tracking Transparency). Android có mô hình quyền theo nhóm và cho phép cấp quyền "chỉ một lần" hay "khi đang dùng app". Việc quản lý memory và quá trình app bị hệ thống "giết" khi chạy nền cũng khác nhau — đặc biệt các máy Trung Quốc như Xiaomi, OPPO có cơ chế tiết kiệm pin rất "hung hăng", thường xuyên tắt tiến trình nền, gây ra lỗi mất thông báo hoặc không đồng bộ dữ liệu mà máy Samsung hay iPhone không gặp.
Distribution: App Store vs Google Play
- App Store (iOS): Quy trình duyệt nghiêm ngặt, review thủ công, có thể mất vài ngày. Không cài đặt được app ngoài store một cách thông thường (trừ TestFlight, enterprise). Điều này ảnh hưởng đến cách bạn phát hành bản test.
- Google Play (Android): Duyệt nhanh hơn, có nhiều kênh (internal/closed/open testing), và cho phép cài file APK/AAB trực tiếp (sideload). Việc này khiến quy trình test bản build linh hoạt hơn.
Tình huống thực tế
Tình huống 1 — Ví điện tử và cái nút Back "biến mất"
Một ví điện tử lớn tại Việt Nam (tạm gọi là app "PayViet") tung ra luồng liên kết ngân hàng mới. Team dev build theo tư duy iOS: mỗi bước có nút "Quay lại" đặt trên header, và họ giả định người dùng luôn bấm nút đó để lùi.
QA test trên iPhone: mọi thứ mượt mà. Nhưng khi phát hành, tổng đài nhận hàng loạt phàn nàn từ người dùng Samsung và Xiaomi: khi đang ở bước xác thực OTP, người dùng bấm nút back hệ thống của Android (cử chỉ vuốt mép trái), app thoát thẳng ra ngoài luồng, mất toàn bộ dữ liệu đã nhập, phải làm lại từ đầu. Tỷ lệ bỏ dở (drop-off) ở bước OTP trên Android cao gấp 3 lần iOS.
Bài học: Nút back hệ thống của Android là một "hành động người dùng" mà iOS không có. Mọi luồng nhiều bước (multi-step flow) đều phải có test case riêng: "bấm nút back hệ thống Android ở từng bước → app phải xử lý đúng (giữ dữ liệu, hỏi xác nhận, hoặc lùi bước hợp lý)". Đây là test case bạn không bao giờ nghĩ ra nếu chỉ test trên iOS.
Tình huống 2 — Thông báo đẩy "bốc hơi" trên máy Xiaomi
Một app giao đồ ăn (giả định là "FoodNow") dựa vào push notification để báo tài xế đã nhận đơn. QA test trên iPhone 13 và Samsung Galaxy S22 — thông báo đến đúng, không lỗi. App lên production.
Vài tuần sau, dữ liệu cho thấy một nhóm người dùng liên tục khiếu nại "không nhận được thông báo đơn hàng". Điều tra ra: gần như toàn bộ nhóm này dùng máy Xiaomi và OPPO đời phổ thông. Nguyên nhân là cơ chế battery optimization cực kỳ mạnh của MIUI/ColorOS: nó tự động "đóng băng" tiến trình nền của app sau vài phút không dùng, chặn luôn cả push notification. iPhone và Samsung xử lý tiến trình nền khoan dung hơn nên QA không phát hiện được.
Bài học: Cùng là "Android", nhưng hành vi quản lý nền và pin của mỗi hãng khác nhau đến mức tạo ra bug riêng. Ma trận thiết bị test cho thị trường Việt Nam bắt buộc phải có ít nhất một máy Xiaomi và một máy OPPO đời phổ thông, không thể chỉ dựa vào Samsung flagship. Với các tính năng phụ thuộc chạy nền (thông báo, đồng bộ, định vị), cần test kịch bản "để app chạy nền lâu → kiểm tra tính năng còn hoạt động không".
Tình huống 3 — Bug thanh toán chỉ xuất hiện trên iOS
Một sàn thương mại điện tử khu vực Đông Nam Á thêm phương thức thanh toán mới. Do Android chiếm phần lớn máy, team ưu tiên test Android trước và làm rất kỹ. iOS chỉ được test "cho có" ở cuối sprint.
Kết quả: một lỗi định dạng số tiền — do khác biệt cách iOS xử lý locale và dấu phân cách hàng nghìn — khiến số tiền "1.500.000đ" hiển thị sai thành "1.5đ" trên một số máy iPhone đặt ngôn ngữ tiếng Việt. Người dùng iOS hoang mang, một số hoàn tất đơn với số tiền hiển thị sai. Dù iOS chỉ chiếm ~25% máy, nhóm này lại là khách chi tiêu cao, nên thiệt hại doanh thu và uy tín rất đáng kể.
Bài học: Không được "ưu tiên theo thị phần máy" một cách máy móc. Với các luồng nhạy cảm (thanh toán, hiển thị tiền tệ, số liệu), cả hai nền tảng phải được test ngang nhau. Khác biệt về xử lý locale, định dạng số, ngày giờ giữa iOS và Android là ổ bug âm thầm nhưng nguy hiểm.
Hướng dẫn từng bước
Đây là quy trình để một Mobile QA tiếp cận một app cần test trên cả hai nền tảng.
Bước 1 — Xác định phân bố người dùng thực tế. Trước khi làm gì, hãy xin dữ liệu analytics (Firebase, Amplitude, hoặc báo cáo của team): tỷ lệ iOS/Android, top các model máy, top các phiên bản OS mà người dùng thật đang dùng. Đừng test trên máy mà người dùng của bạn không có.
Bước 2 — Xây ma trận thiết bị (device matrix). Từ dữ liệu bước 1, lập bảng thiết bị cần phủ. Với thị trường Việt: tối thiểu 1-2 iPhone (một đời mới, một đời cũ hơn), và phía Android cần đa dạng hãng — 1 Samsung, 1 Xiaomi, 1 OPPO/Vivo — trải trên ít nhất 2-3 phiên bản OS. Ưu tiên máy tầm trung/giá rẻ vì đó là số đông người dùng thật.
Bước 3 — Phân loại test case theo mức độ nền tảng. Chia test case thành ba nhóm: (a) Chung — logic nghiệp vụ giống nhau ở cả hai (ví dụ: đăng nhập sai mật khẩu báo lỗi đúng). (b) Riêng iOS — nút back góc trái, vuốt mép, share sheet, App Tracking Transparency. (c) Riêng Android — nút back hệ thống, tiến trình nền/battery optimization, đa dạng độ phân giải màn hình, quyền theo nhóm.
Bước 4 — Test song song và ghi chú khác biệt. Chạy cùng một kịch bản trên cả hai nền tảng cạnh nhau. Khi thấy hành vi khác nhau, phân biệt rõ: đây là khác biệt có chủ đích (do đúng quy ước nền tảng) hay là bug (do dev quên xử lý). Đây là kỹ năng phán đoán quan trọng nhất của Mobile QA.
Bước 5 — Kiểm tra sự tuân thủ quy ước nền tảng. Đảm bảo app "cảm giác đúng chất iOS" trên iOS và "đúng chất Android" trên Android, không phải một bản sao cứng nhắc của nền tảng kia.
Bước 6 — Báo cáo bug kèm ngữ cảnh nền tảng. Khi log bug, luôn ghi rõ nền tảng, model máy, và phiên bản OS. Bug "chỉ xảy ra trên Android 10 máy Xiaomi" là thông tin vàng giúp dev tái hiện.
Lỗi thường gặp & mẹo
- Lỗi "test iOS xong coi như xong Android". Đây là sai lầm chết người đã nêu ở đầu bài. Không bao giờ suy diễn kết quả từ nền tảng này sang nền tảng kia, đặc biệt với điều hướng, quyền, thông báo, và định dạng dữ liệu.
- Chỉ test trên flagship. Nhiều QA chỉ có iPhone Pro và Samsung đời cao trong tay. Nhưng người dùng thật phần lớn dùng máy giá rẻ, RAM thấp, màn hình nhỏ. Bug tràn chữ, giật lag, hết bộ nhớ chỉ lộ ra trên máy yếu.
- Bỏ qua battery optimization của các hãng Trung Quốc. Như tình huống 2 — đây là nguồn bug lớn ở Việt Nam mà rất dễ bị bỏ sót. Mẹo: luôn có kịch bản "app chạy nền lâu" cho mọi tính năng phụ thuộc tiến trình nền.
- Quên nút back hệ thống Android. Mẹo vàng: với mọi luồng nhiều bước, bấm nút back hệ thống ở TỪNG bước và quan sát. Đây là một trong những test case tìm ra nhiều bug nhất trên Android.
- Không phân biệt "khác biệt có chủ đích" với "bug". Đừng log bug kiểu "trên iOS nút này ở dưới mà Android lại ở trên". Hãy tra HIG và Material Design trước khi kết luận — có thể đó là hành vi ĐÚNG của nền tảng.
- Mẹo dùng emulator/simulator hợp lý. Có thể dùng máy ảo để test nhanh các case chung, nhưng những khác biệt về pin, thông báo, hiệu năng, cảm biến thì bắt buộc phải test trên máy thật. (Bài 5 sẽ đào sâu chủ đề này.)
Bài tập thực hành
- Lập device matrix cho một app Việt. Chọn một app bạn biết (ví dụ một ví điện tử hoặc app giao hàng). Giả định phân bố 72% Android / 28% iOS. Hãy đề xuất một ma trận 5-6 thiết bị cụ thể (nêu rõ model, hãng, phiên bản OS) đủ để phủ rủi ro chính, và giải thích lý do chọn từng máy.
- Săn khác biệt điều hướng. Lấy một app bất kỳ có sẵn trên cả iOS và Android. Với một luồng 3 bước (ví dụ: thêm sản phẩm vào giỏ → nhập địa chỉ → xác nhận), thực hiện thao tác "back" theo cách riêng của từng nền tảng ở mỗi bước, ghi lại hành vi. Chỉ ra ít nhất một điểm khác biệt và phán đoán: đó là chủ đích hay bug?
- Phân loại test case. Cho tính năng "đăng nhập bằng số điện thoại + OTP", hãy viết 6 test case và gắn nhãn mỗi case là Chung / Riêng iOS / Riêng Android. Cố gắng nghĩ ra ít nhất một case riêng cho mỗi nền tảng.
Tóm tắt
iOS và Android là hai thế giới khác nhau về ecosystem, thiết kế, phân phối và hành vi hệ thống — chứ không phải hai phiên bản của cùng một app. Với QA, những khác biệt cốt lõi cần nhớ là: fragmentation khiến Android khó test hơn nhiều (đa hãng, đa OS, đa màn hình); nút back hệ thống và battery optimization là hai nguồn bug đặc trưng của Android, đặc biệt trên máy Xiaomi/OPPO phổ biến ở Việt Nam; iOS nghiêm ngặt về quyền riêng tư và có quy trình duyệt App Store chặt chẽ. Nguyên tắc hành động: đừng bao giờ suy diễn kết quả từ nền tảng này sang nền tảng kia, xây ma trận thiết bị dựa trên người dùng thật (ưu tiên máy giá rẻ), phân loại test case theo mức độ nền tảng, và luôn phân biệt khác biệt có chủ đích với bug thật sự. Nắm vững nền tảng chính là nền móng cho mọi bài học automation và chuyên sâu phía sau trong khóa học này.