Quy mô và hiệu năng
Test runtime permission thế nào
Bài kiểm thử đặc thù mobile nói mỗi quyền phải test đủ sáu trạng thái. Bài này nói đưa quyền về từng trạng thái bằng lệnh gì, vì sao Android không phân biệt được "chưa hỏi" với "deny vĩnh viễn", và phần nào máy chặn được.
Nội dung bài
Kiểm thử đặc thù mobile liệt kê sáu trạng thái mỗi quyền phải đi qua. Bài đó dừng ở phải làm gì. Bài này là phần làm bằng cách nào — lệnh đưa quyền về từng trạng thái, một cái bẫy của Android làm app xử lý sai trạng thái ngay từ đầu, và phần nhỏ mà máy chặn được.
Đưa quyền về từng trạng thái bằng lệnh gì
Không trạng thái nào cần gỡ app cài lại. Gỡ cài lại làm mất luôn dữ liệu local, tức là đổi sang một kịch bản khác mà không biết.
adb shell pm reset-permissionsxcrun simctl privacy <device> reset all <bundle-id>adb shell pm grant <package> android.permission.CAMERAxcrun simctl privacy <device> grant camera <bundle-id>adb shell pm revoke <package> <permission> — lệnh này giết luôn tiến trình app, đó là hành vi thật của hệ thốngxcrun simctl privacy <device> revoke camera <bundle-id>pm reset-permissionsAndroid không phân biệt được "chưa hỏi" với "deny vĩnh viễn"
Đây là chỗ app xử lý sai ngay từ dòng code đầu tiên, và không có test nào bắt được nếu không biết trước.
- Chưa hỏi lần nào
hàm kiểm tra "có nên giải thích không" trả về false
- Đã hỏi, user deny một lần
trả về true — đây là lúc app giải thích rồi hỏi lại
- User deny lần thứ hai
trả về false trở lại — giống hệt trạng thái chưa hỏi lần nào
iOS không có bẫy này
iOS trả về trạng thái riêng cho "chưa quyết định" và "đã từ chối". Code hai nền tảng vì thế không đối xứng — đừng bê logic iOS sang Android rồi tin là xong.
Vì sao đáng để làm đúng
Tỷ lệ deny vĩnh viễn của Notification 5% ở 500.000 user là 25.000 người không bao giờ nhận được nhắc hạn Task. Nút bấm không phản ứng đẩy con số đó lên, vì user bấm vài lần rồi bỏ.
Sáu trạng thái, chạy bằng người, cho từng quyền
Chạy trọn vòng cho từng quyền một. Trộn hai quyền trong một vòng thì không biết trạng thái nào gây ra kết quả nào.
Reset về như mới cài
pm reset-permissions, rồi mở app từ launcher.Đi tới đúng chức năng cần quyền
Ghi lại dialog hiện ra ở màn hình nào. Hiện ở màn hình đầu tiên là không đạt, dừng luôn, không cần chạy tiếp.
Deny lần một
App phải giải thích vì sao cần và còn đường thử lại. Im lặng quay về là không đạt.
Deny lần hai
App không được hỏi lại vô ích. Phải chỉ đường ra Settings, và đường đó phải bấm được chứ không phải một câu chữ.
Cấp quyền từ Settings rồi quay lại app
Trên Android việc này giết tiến trình app — app khởi động lại từ số không. Kiểm luôn: quay lại có về đúng chỗ đang dở không, xem Test app lifecycle thế nào.
Chụp đủ sáu ảnh
Lưu cùng tài liệu màn hình. Người sau không phải dựng lại sáu trạng thái này từ đầu.
Cái gì máy chặn được
Phần này nhỏ, và biết nó nhỏ là quan trọng — đừng hứa với ai rằng CI lo được nhóm này.
Chạy máy, mỗi pull request
Một luật lint hoặc một test đơn giản: cấm gọi hàm xin quyền trong màn hình khởi động. Đây là lỗi tốn kém nhất và cũng là lỗi duy nhất máy bắt chắc chắn được.
Chạy máy, mỗi đêm
UI test chạy với quyền cấp sẵn qua pm grant. Nhớ rằng đây là test luồng chính, không phải test permission — nó cố tình bỏ qua toàn bộ năm trạng thái còn lại.
Chạy người, mỗi khi màn hình đổi
Sáu bước ở trên. Dialog của hệ điều hành không tự động hoá rẻ được, và chữ trong câu giải thích là quyết định sản phẩm chứ không phải quyết định code.
Không tự động hoá
Kịch bản thu hồi quyền khi app đang chạy. Lệnh revoke giết tiến trình, nên test tự động không quan sát được app phản ứng ra sao — phần đó thuộc về nhóm lifecycle.
Giới hạn
Simulator và emulator không có người thật
Chúng dựng được trạng thái, không dựng được phản ứng. Câu giải thích viết dở thì máy vẫn báo xanh — chỉ người đọc mới thấy nó khó hiểu.
Đổi câu giải thích là đổi số liệu
Tỷ lệ deny vĩnh viễn theo từng quyền phải đo liên tục, xem Sự kiện đo lường. Không đo thì không biết câu chữ mới tốt hơn hay tệ hơn câu cũ.

