Mở đầu — vì sao bài này quan trọng
Nếu bạn từng làm QA cho một ứng dụng có mua hàng trong app — gói premium, xu ảo, cởi khoá tính năng — thì bạn biết rằng đây là phần "chạm tiền thật" của sản phẩm. Một lỗi ở màn hình đăng nhập gây khó chịu, nhưng một lỗi ở luồng thanh toán khiến công ty mất doanh thu trực tiếp hoặc tệ hơn là bị người dùng phàn nàn rằng đã trừ tiền mà không nhận được hàng. Với Android, luồng này gần như luôn đi qua Google Play Billing — hệ thống thanh toán bắt buộc của Google cho các sản phẩm số bên trong app.
Ở bài trước (Bài 22) chúng ta đã mổ xẻ IAP trên iOS với StoreKit và sandbox của Apple. Bài này tập trung riêng vào thế giới Android: Google Play Billing Library, luồng test bằng Internal Testing track trong Play Console, cơ chế license tester, và những "thẻ test ma thuật" cho phép bạn giả lập mua thành công, bị từ chối, hay thẻ hết hạn — mà không tốn một đồng nào.
Đây là kỹ năng mà rất nhiều QA Việt Nam bị hổng, vì các đội thường nghĩ "cứ để dev test là được". Nhưng thực tế, QA hiểu billing sẽ là người phát hiện ra những bug đắt giá nhất: mua thành công nhưng app không grant quyền, mua lại bị tính tiền hai lần, hay subscription không gia hạn đúng. Hãy cùng đi vào chi tiết.
Khái niệm cốt lõi
Google Play Billing là gì và tại sao bạn không test được như thanh toán thường
Google Play Billing là bộ API mà app Android dùng để bán sản phẩm số: in-app products (mua một lần, ví dụ 500 xu) và subscriptions (thuê bao định kỳ, ví dụ gói premium 99.000đ/tháng). Điểm mấu chốt bạn phải nhớ: giao dịch không chạy qua server của công ty bạn, mà chạy qua hạ tầng của Google. App của bạn chỉ "nói chuyện" với Play Store trên máy qua Billing Library; Play Store mới là bên xử lý tiền.
Hệ quả cho QA: bạn không thể test IAP bằng cách build app rồi cài trực tiếp qua Android Studio (sideload). Google Play chỉ chấp nhận giao dịch cho các app đã được upload lên Play Console với đúng applicationId và được ký bằng đúng chữ ký mà Google biết. Đây là rào cản đầu tiên khiến rất nhiều bạn mới vào nghề loay hoay: "sao tôi bấm mua mà nó báo item không tồn tại?".
Các loại sản phẩm cần phân biệt khi test
- Consumable (tiêu hao): mua rồi dùng hết, mua lại được. Ví dụ: gói 100 kim cương trong game. Sau khi grant, app phải gọi consume để người dùng có thể mua tiếp.
- Non-consumable (không tiêu hao): mua một lần, sở hữu vĩnh viễn. Ví dụ: gói "gỡ quảng cáo". App phải gọi acknowledge trong vòng 3 ngày, nếu không Google tự động hoàn tiền.
- Subscription (thuê bao): gia hạn định kỳ, có trạng thái phức tạp (active, in grace period, on hold, paused, canceled).
acknowledge cho non-consumable, và người dùng bị hoàn tiền tự động sau 3 ngày dù họ không hề yêu cầu.License tester — chìa khoá để test miễn phí
License tester là danh sách email (giới hạn tối đa 100 tài khoản) mà bạn khai báo trong Play Console tại mục Settings → License testing. Khi một tài khoản Google nằm trong danh sách này mua hàng trên app của bạn, Google không thực sự thu tiền. Thay vào đó, họ được dùng các phương thức thanh toán test đặc biệt và giao dịch sẽ tự động hoàn (nếu là thật) hoặc không phát sinh phí.
Điểm hay của license tester: nó hoạt động trên mọi track (internal, closed, open) và cả với build phát hành, miễn là email đó nằm trong danh sách. Đây là công cụ chính bạn dùng hằng ngày.
Test cards — "thẻ luôn approve" và "thẻ luôn từ chối"
Với tài khoản license tester, khi bấm mua, ở màn hình chọn phương thức thanh toán bạn sẽ thấy các lựa chọn dạng "Test instrument":
- Test card, always approves — giao dịch luôn thành công. Dùng để test luồng "happy path": mua xong app grant quyền đúng.
- Test card, always declines — giao dịch luôn bị từ chối. Dùng để test app xử lý lỗi thanh toán ra sao.
- Slow test card, approves after a few minutes — mô phỏng thanh toán chậm (pending). Cực kỳ quan trọng để test trạng thái PENDING — luồng mà nhiều QA quên hẳn.
Tình huống thực tế
Tình huống 1 — Startup edtech ở TP.HCM và bug "mua rồi mà vẫn khoá"
Một startup edtech giả định tên HocNhanh, làm app luyện thi IELTS, bán gói "Mở khoá toàn bộ đề" giá 199.000đ (non-consumable). Đội dev test bằng máy cá nhân, thấy "mua xong mở được đề" nên yên tâm phát hành. Ba ngày sau, hàng loạt người dùng báo: "Em trả tiền rồi mà giờ lại bị khoá lại, và tiền cũng được hoàn về tài khoản?!".
Nguyên nhân: dev đã grant quyền ngay khi nhận purchase, nhưng quên gọi acknowledgePurchase(). Theo chính sách Google, mọi giao dịch không được acknowledge trong 72 giờ sẽ bị hoàn tiền tự động và thu hồi quyền. QA trong đội không biết luật này nên không có test case cho nó — vì trên máy dev, họ chỉ test trong vài phút, không đủ 72 giờ để lộ bug.
Bài học: QA phải có test case kiểm tra rằng sau khi mua, app acknowledge trong thời hạn. Cách kiểm nhanh: sau khi mua bằng test card, dùng Google Play Developer API hoặc kiểm tra trạng thái acknowledgementState của giao dịch để chắc chắn nó đã chuyển sang "acknowledged". Không được chỉ tin vào UI.
Tình huống 2 — Đội game ở Hà Nội và bẫy "mua hai lần tính tiền hai lần"
Một studio game giả định tên PixelBird, bán gói 500 kim cương (consumable). QA test happy path OK. Nhưng một tester tinh ý dùng Slow test card để test trạng thái pending: bấm mua, app hiển thị "đang xử lý", tester nóng ruột đóng app rồi mở lại và bấm mua lần nữa. Kết quả: khi giao dịch chậm hoàn tất, người chơi bị grant 1000 kim cương nhưng chỉ định mua 500, còn ở lần khác lại thấy nút mua bị kẹt vì món hàng consumable chưa được consume.
Nguyên nhân gốc: app không xử lý đúng trạng thái PENDING và không query lại purchases khi khởi động (queryPurchasesAsync). Với consumable, nếu app không gọi consume, Google coi như người dùng vẫn đang sở hữu món đó và sẽ chặn lần mua tiếp theo — gây ra bug "không mua được nữa".
Bài học: Luôn có test case cho luồng pending (dùng Slow test card), và test kịch bản kill app giữa chừng rồi mở lại để xác minh app khôi phục và xử lý giao dịch treo. Đây là loại bug mà chỉ QA hiểu billing mới nghĩ ra được.
Tình huống 3 — Sàn TMĐT Đông Nam Á và chuyện chọn nhầm track
Một đội QA tại một công ty fintech giả định phục vụ thị trường Đông Nam Á upload build lên Closed Testing track để test billing, nhưng mất gần nửa ngày vì "mua cứ báo lỗi item không khả dụng". Hoá ra sản phẩm IAP họ tạo trong Play Console vẫn ở trạng thái Inactive, và bản build billing đầu tiên chưa từng được "rollout" nên Google chưa index được product ID. Ngoài ra máy test dùng tài khoản chưa được thêm vào danh sách tester của track đó.
Bài học: Ba điều kiện phải đồng thời đúng thì IAP mới test được: (1) sản phẩm ở trạng thái Active, (2) build có chứa Billing đã được publish lên ít nhất một track (dù là internal), và (3) tài khoản Google trên máy vừa là tester của track vừa là license tester. Thiếu một là hỏng. Với người mới, Internal Testing track là lựa chọn tốt nhất vì nó cập nhật gần như tức thì (vài phút), không cần Google review.
Hướng dẫn từng bước
Dưới đây là quy trình chuẩn để một QA thiết lập môi trường test Google Play Billing từ số không.
- Chuẩn bị build có tích hợp Billing Library. Yêu cầu dev cung cấp bản build (AAB) đã tích hợp Play Billing Library và tăng versionCode so với bản trên Play. Build phải được ký bằng chữ ký mà Play Console biết (thường là Play App Signing).
- Upload lên Internal Testing track. Vào Play Console → Testing → Internal testing → Create new release → upload AAB → Save → Review release → Start rollout. Track này không cần Google duyệt, chỉ mất vài phút để sẵn sàng.
- Thêm testers cho track. Trong Internal testing, tab Testers, tạo hoặc chọn một email list và thêm các tài khoản Google của người test. Copy opt-in URL và gửi cho tester để họ bấm "Become a tester".
- Khai báo License testers. Vào Play Console (cấp tài khoản, không phải cấp app) → Settings → License testing, thêm đúng các email đó (tối đa 100). Đây là bước cho phép dùng test card miễn phí. Chọn License response là
RESPOND_NORMALLY.
- Tạo sản phẩm IAP. Vào Monetize → Products → In-app products (cho consumable/non-consumable) hoặc Subscriptions. Tạo product với Product ID khớp chính xác với code, đặt giá, và Activate sản phẩm.
- Cài app qua Play Store trên thiết bị thật. Trên điện thoại đăng nhập bằng tài khoản tester, mở opt-in URL, bấm cài. Bắt buộc cài qua Play Store, không sideload. Đảm bảo chỉ có một tài khoản Google trên máy để tránh nhầm.
- Thực thi test case. Bấm mua → xác minh màn hình thanh toán hiện test instrument → chọn always approves để test happy path, always declines cho luồng lỗi, slow test card cho pending.
- Xác minh phía sau UI. Đừng dừng ở "thấy grant quyền là xong". Kiểm tra trạng thái
acknowledged/consumed, kiểm tra app khôi phục đúng khi mở lại (queryPurchasesAsync), và với subscription thì kiểm tra vòng đời qua thời gian rút gọn của Google (subscription test gia hạn rất nhanh, ví dụ chu kỳ tháng chỉ mất vài phút).
Lỗi thường gặp & mẹo
- "Item not available for purchase" / "không tìm thấy sản phẩm": thủ phạm phổ biến nhất. Kiểm tra theo thứ tự: product ID có khớp chính xác không (phân biệt hoa thường), sản phẩm đã Active chưa, build đã publish lên track chưa, tài khoản đã opt-in tester chưa. Sau khi upload build lần đầu thường phải chờ vài giờ để Google index billing.
- Không thấy test card: email chưa nằm trong License testing, hoặc máy đang đăng nhập tài khoản khác. Xoá bớt tài khoản Google phụ trên máy test.
- Quên test PENDING: rất nhiều đội chỉ test happy path. Luôn dùng Slow test card để test trạng thái pending, và xác minh app không grant quyền sớm khi giao dịch chưa hoàn tất.
- Quên acknowledge (non-consumable/subscription): dẫn tới hoàn tiền tự động sau 72 giờ. Đây là bug "ẩn" vì nó chỉ lộ sau 3 ngày. Hãy đưa việc kiểm tra
acknowledgementStatevào checklist.
- Nhầm consumable/non-consumable: consumable phải
consumemới mua lại được; non-consumable thì không. Test cả hai luồng "mua lại".
- Mẹo về hoàn tiền để reset: khi test xong, nếu giao dịch còn treo, bạn có thể vào Order Management trong Play Console để hoàn/huỷ, giúp reset trạng thái sở hữu để test lại từ đầu.
- Mẹo về subscription: dùng đồng hồ gia hạn rút gọn của Google để quan sát các trạng thái grace period và account hold — đây là nơi phát sinh nhiều bug thực tế nhất về mất/khôi phục quyền.
Bài tập thực hành
- Thiết lập môi trường: Cùng một app mẫu (hoặc app của đội bạn), hãy tự tay upload lên Internal Testing track, thêm chính email của bạn vào cả tester list lẫn license testing, tạo một sản phẩm consumable và một non-consumable, rồi cài app qua Play Store. Ghi lại thời gian từ lúc upload đến lúc mua được — bạn sẽ hiểu độ trễ index của Google.
- Viết bộ test case: Soạn ít nhất 8 test case bao phủ: mua thành công (approve), mua bị từ chối (decline), giao dịch pending (slow card), kill app khi đang pending rồi mở lại, mua lại consumable sau khi consume, xác minh acknowledge cho non-consumable, khôi phục quyền sau khi cài lại app, và người dùng KHÔNG phải tester thì không mua bằng test card được.
- Săn bug acknowledge: Cố tình để một giao dịch non-consumable không được acknowledge, chờ (hoặc mô phỏng) và mô tả điều gì sẽ xảy ra sau 72 giờ. Viết một bug report chuẩn cho tình huống này với đầy đủ bối cảnh, hậu quả doanh thu, và cách reproduce.
Tóm tắt
Google Play Billing là luồng "chạm tiền thật" của app Android, và điểm cốt lõi bạn phải nhớ là giao dịch chạy qua Google, không qua server công ty bạn — nên không thể test bằng sideload. Công cụ chính của QA là Internal Testing track (cập nhật nhanh, không cần duyệt), license testers (tối đa 100 email, cho phép test miễn phí), và các test card always approves / always declines / slow (pending).
Ba điều kiện phải cùng đúng để test được: sản phẩm Active, build có Billing đã publish lên track, và tài khoản vừa là tester vừa là license tester. Quan trọng nhất, đừng dừng ở UI: hãy xác minh acknowledge/consume, luồng pending, và khả năng khôi phục khi mở lại app — vì đó là nơi ẩn những bug đắt giá nhất, như câu chuyện HocNhanh bị hoàn tiền tự động và PixelBird bị kẹt nút mua. Nắm chắc bài này, bạn không chỉ "test được IAP" mà còn trở thành người bảo vệ doanh thu cho sản phẩm.