Product Management
Đăng nhập
ESC

Nhập từ khóa để tìm kiếm

↑↓ Di chuyển
Enter Mở
ESC Đóng

Bài 50 — Mobile Test Reporting & Dashboards

Đã đọc 0/13 mục · còn khoảng 12 phút
Cách chúng tôi ghi nhận

Một mục được tính là đã đọc khi nó nằm giữa màn hình đủ lâu so với độ dài của nó (bảng và sơ đồ tính một nửa), bạn vẫn đang cuộn hoặc bấm phím, và bạn đã thấy tới cuối mục. Lướt nhanh hoặc để tab mở không được tính. Chúng tôi chỉ lưu thời gian đọc từng mục — không lưu gì khác.

Mở đầu — vì sao bài này quan trọng

Hãy tưởng tượng bạn vừa chạy xong một đêm regression trên 800 test case Appium cho ứng dụng ngân hàng số. Sáng ra, sếp hỏi: "Đêm qua chạy thế nào?". Nếu câu trả lời của bạn là "Ừm… hình như có mấy cái fail, để em mở terminal xem lại" thì bạn đã thua ngay từ vòng gửi xe. QA giỏi không phải người chạy được test — máy CI cũng chạy được — mà là người biến kết quả test thành một câu chuyện rõ ràng, đáng tin, ra được quyết định cho cả team đọc trong 30 giây.

Đó chính là chủ đề của Bài 50: Test Reporting & Dashboards cho mobile. Trên mobile, việc report khó hơn web rất nhiều. Một test fail trên web bạn còn mở lại browser xem được; nhưng một test fail trên con Samsung A15 chạy Android 14 lúc 2 giờ sáng trên device farm thì bạn không thể tái hiện nếu không có bằng chứng thu thập ngay tại thời điểm fail. Screenshot, video, logcat, và cả trạng thái thiết bị — nếu không chụp lại lúc đó, chúng biến mất vĩnh viễn.

Trong bài này chúng ta tập trung hẹp vào một run test cần xuất ra cái gì, tổ chức bằng chứng ra sao, và dựng dashboard theo dõi xu hướng thế nào để cả developer, QA lead và PM đều đọc được. Chúng ta sẽ không đi sâu vào cách viết test (Bài 9, 10), cách setup CI (Bài 48) hay device farm (Bài 49) — những phần đó có bài riêng. Ở đây, nhân vật chính là báo cáo — sản phẩm cuối cùng mà thế giới bên ngoài nhìn thấy từ công sức QA của bạn.

Khái niệm cốt lõi

Một test run cần xuất ra những gì?

Mỗi lần chạy test, tối thiểu bạn phải thu được năm nhóm dữ liệu. Hãy nhớ chúng như một bộ hồ sơ điều tra hiện trường:

1. Kết quả tổng hợp (pass/fail/skip count). Con số biết nói: 782 pass, 15 fail, 3 skipped. Nhưng con số trần trụi thì vô nghĩa — bạn cần thêm pass rate (97.7%) và so sánh với run trước. Một run 97% có thể là tuyệt vời hoặc thảm họa, tùy vào hôm qua nó là 99.5% hay 92%.

2. Thời lượng (duration). Không chỉ tổng thời gian run, mà duration của từng test. Trên mobile, một test bỗng nhiên chạy từ 8 giây lên 40 giây thường là dấu hiệu của app launch chậm, animation bị treo, hoặc emulator quá tải — những thứ này báo trước một bug performance trước cả khi nó fail hẳn.

3. Screenshot tại điểm fail. Đây là bằng chứng số một. Khoảnh khắc assertion fail, framework phải chụp ngay màn hình app. Không phải screenshot cuối cùng của test — mà đúng frame lúc "nút Đăng nhập lẽ ra phải hiện nhưng không thấy đâu".

4. Video record của test fail. Screenshot cho bạn "hiện trường", video cho bạn "diễn biến". Rất nhiều bug mobile là bug thời gian: element xuất hiện rồi biến mất, toast hiện 0.5 giây, transition kẹt giữa chừng. Chỉ video mới bắt được. Mẹo thực chiến: chỉ giữ video của test fail, xóa video test pass, nếu không đĩa của bạn sẽ đầy trong một đêm.

5. Log thiết bị (logcat cho Android / oslog cho iOS). Đây là phần mà QA mới hay bỏ quên nhưng developer cần nhất. Khi app crash, log native chứa stack trace, exception, NullPointerException, EXC_BAD_ACCESS… Nếu bạn nộp bug mà thiếu logcat, dev sẽ đá lại ngay: "reproduce đi rồi lấy log".

Ba tầng người đọc báo cáo

Một sai lầm kinh điển là dựng một report cho tất cả mọi người. Thực tế có ba đối tượng với ba nhu cầu khác nhau:

  • Developer cần chi tiết: stack trace, log, video, để fix. Họ đọc report của từng test fail.
  • QA Lead cần xu hướng: pass rate theo thời gian, flaky test nào tái phát, module nào hay vỡ. Họ đọc dashboard.
  • PM / Stakeholder cần một câu: "Build này ready để release chưa?". Họ đọc một dòng tóm tắt màu xanh/đỏ.
Report tốt phục vụ được cả ba tầng, theo kiểu kim tự tháp ngược: trên cùng là kết luận một dòng, xuống dưới là chi tiết cho ai muốn đào sâu.

Từ report tĩnh đến dashboard động

Report là ảnh chụp một run. Dashboard là phim quay nhiều run theo thời gian. Sức mạnh thật sự nằm ở dashboard, vì nó trả lời được những câu hỏi mà một report đơn lẻ không trả lời được: "Pass rate của chúng ta đang đi lên hay đi xuống trong 2 tuần qua?", "Test nào flaky nhất tháng này?", "Suite chạy ngày càng chậm — tại sao?". Công cụ phổ biến: Allure Report (đẹp, dễ dùng, tích hợp screenshot/video/step tốt), ReportPortal (mạnh về AI phân loại lỗi và lịch sử flaky), hoặc dashboard tự dựng bằng Grafana đọc từ database.

Tình huống thực tế

Tình huống 1 — Tiki và cái bẫy "báo cáo chỉ có màu đỏ"

Một team QA tại sàn TMĐT lớn ở TP.HCM (gọi là "TikiClone" cho tiện) chạy 1.200 test Appium mỗi đêm trên 6 loại thiết bị. Report ban đầu của họ chỉ là output thô của TestNG: một danh sách dài các dòng PASS/FAIL trong console CI. Mỗi sáng, QA mất gần 2 tiếng để lọc thủ công xem fail nào là bug thật, fail nào chỉ là flaky.

Vấn đề cốt lõi: report không phân biệt được fail lặp lại và fail ngẫu nhiên. Họ chuyển sang Allure, cấu hình đính kèm screenshot + video + logcat vào mỗi test fail, và bật tính năng history. Ngay tuần đầu, dashboard chỉ ra một sự thật gây sốc: 11 trong số 15 "bug" mỗi đêm thực chất là cùng một test flaky ở màn hình thanh toán, fail do wait không đủ khi mạng chậm. Không phải 15 bug — chỉ có 4 bug thật và 1 test cần fix.

Bài học: báo cáo không phân tầng và không có lịch sử sẽ khiến bạn tưởng chất lượng đang tệ, trong khi thật ra chỉ là một test viết ẩu đang gào lên mỗi đêm. Số lượng fail không quan trọng bằng số lượng vấn đề riêng biệt.

Tình huống 2 — Ứng dụng gọi xe và cái crash không ai chụp lại được

Một startup gọi xe ở Đông Nam Á có bug: app crash khi người dùng chuyển từ màn hình bản đồ sang lịch sử chuyến đi, nhưng chỉ trên vài dòng máy Xiaomi đời cũ. Test tự động có bắt được fail này — nhưng report chỉ ghi vỏn vẹn "App crashed, session terminated". Không screenshot (vì app đã chết), không log native. Dev nhìn report xong lắc đầu: "Không đủ thông tin".

Team sửa lại hook thu thập bằng chứng: cấu hình để logcat/oslog được stream ra file liên tục trong suốt test, không phải chụp sau khi fail. Nhờ vậy, ngay cả khi app crash đột ngột, họ vẫn có toàn bộ log ngay trước thời điểm chết. Lần chạy sau, log chỉ rõ một OutOfMemoryError do bitmap bản đồ không được giải phóng. Dev fix trong nửa ngày.

Bài học: với những fail dạng crash, screenshot-sau-fail là vô dụng vì app đã không còn màn hình. Bạn phải thu log theo kiểu liên tục (streaming) chứ không phải kiểu chụp một khoảnh khắc. Đây là khác biệt sống còn của reporting trên mobile so với web.

Tình huống 3 — Fintech và một dòng report cứu buổi họp release

Một công ty fintech tại Hà Nội chạy CI cho app ví điện tử. Mỗi build tạo pull request, và họ cấu hình bot tự động comment thẳng vào PR một dòng tóm tắt: "✅ 312/315 pass (99%) · 3 skip · 8p12s · [Xem báo cáo đầy đủ]" kèm link Allure. PM và dev thấy ngay trong GitHub, không cần mở CI.

Một hôm, con số hiện "❌ 298/315 pass (94.6%)" với 12 fail đều nằm ở module KYC. Nhờ dashboard phân nhóm theo module, QA Lead nhìn phát biết ngay: không phải test hỏng, mà là một thay đổi API xác thực đã phá vỡ luồng KYC. Build bị chặn release, tránh được sự cố đẩy bug lên tay hàng chục nghìn người dùng thật.

Bài học: report giá trị nhất không phải cái đẹp nhất, mà cái đến đúng nơi người ta ra quyết định — ngay trong PR, ngay trong Slack — và phân nhóm đủ tốt để chỉ ra "vỡ ở đâu" chỉ trong một cái liếc mắt.

Hướng dẫn từng bước

Đây là quy trình dựng hệ thống reporting hoàn chỉnh cho một suite mobile:

Bước 1 — Chuẩn hóa việc thu bằng chứng ở tầng framework. Viết một listener/hook chạy tự động khi mỗi test kết thúc (ví dụ afterEach trong WebdriverIO, hoặc ITestListener.onTestFailure trong TestNG). Trong hook này: nếu test fail thì chụp screenshot, dừng và lưu video, và pull file log về. Đừng bao giờ để việc thu bằng chứng nằm rải rác trong từng test — nó phải tự động và tập trung.

Bước 2 — Bật video và log ngay từ khi khởi động session. Với Appium, bật record_video từ đầu test qua driver; với logcat, chạy adb logcat xuất ra file ngay khi session bắt đầu (streaming). Với iOS, thu oslog qua công cụ tương ứng. Nhớ: bắt đầu thu từ đầu, quyết định giữ hay xóa ở cuối tùy pass/fail.

Bước 3 — Đính kèm bằng chứng vào report. Dùng API của công cụ report (ví dụ allure.attachment()) để gắn screenshot, video, log vào đúng test tương ứng. Mục tiêu: người mở report click vào một test fail là thấy ngay cả ba loại bằng chứng, không phải đi lục folder.

Bước 4 — Bổ sung metadata môi trường. Mỗi report phải ghi: tên thiết bị, phiên bản OS, version app (build number), commit hash, thời gian chạy. Thiếu những thứ này, một bug "chỉ xảy ra trên Android 12" sẽ mãi mãi là bí ẩn.

Bước 5 — Sinh report và publish. Cuối run, sinh HTML report và publish lên nơi mọi người truy cập được (GitHub Pages, S3, hoặc artifact của CI). Đừng để report nằm trong máy CI rồi bị xóa sau 24 giờ.

Bước 6 — Đẩy tóm tắt tới nơi ra quyết định. Cấu hình bot comment PR và/hoặc gửi Slack/Telegram một dòng tóm tắt kèm link. Đây là bước biến report từ "tài liệu bị bỏ quên" thành "công cụ team dùng hằng ngày".

Bước 7 — Bật history để dựng dashboard xu hướng. Cấu hình lưu lịch sử các run (Allure history, hoặc ghi kết quả vào database + Grafana). Từ đây bạn theo dõi được pass rate trend, flaky rate, và duration trend theo thời gian.

Lỗi thường gặp & mẹo

Lỗi 1 — Chỉ chụp screenshot cuối test thay vì tại điểm fail. Nhiều người đặt screenshot ở cuối afterEach mà quên rằng app có thể đã điều hướng đi chỗ khác. Hãy chụp ngay tại thời điểm assertion ném lỗi.

Lỗi 2 — Lưu video cho cả test pass. Một suite 1.000 test có thể tạo hàng chục GB video mỗi đêm. Chỉ giữ video của test fail (và có thể vài test flaky). Xóa phần còn lại tự động.

Lỗi 3 — Quên metadata thiết bị. Bug mobile 90% liên quan đến device cụ thể. Report không ghi "Samsung A15 / Android 14" thì gần như vô dụng cho việc điều tra.

Lỗi 4 — Coi flaky là pass hoặc là fail một cách cứng nhắc. Một test lúc pass lúc fail cần được đánh dấu là flaky riêng, không trộn vào con số fail thật. Nếu không, dashboard của bạn sẽ luôn "đỏ" và team dần dần mất niềm tin, bỏ qua cả bug thật (hiệu ứng "chuông báo động kêu hoài nên tắt luôn").

Lỗi 5 — Report quá dài, không ai đọc. Một report 20 trang không phân tầng thì cũng như không có. Luôn có một dòng kết luận trên cùng.

Mẹo vàng: đặt câu hỏi thử nghiệm — "Nếu tôi đưa report này cho một dev chưa từng thấy bug này, họ có fix được không cần hỏi lại tôi câu nào không?". Nếu chưa, report của bạn còn thiếu bằng chứng. Đó là thước đo chất lượng report tốt nhất.

Mẹo về flaky: dùng dashboard tính flaky rate (số lần đổi trạng thái pass↔fail trên tổng số run gần đây). Ưu tiên fix top 5 test flaky mỗi sprint — thường chỉ cần vài test được "chữa" là pass rate tổng ổn định hẳn.

Bài tập thực hành

  • Thiết kế bộ hồ sơ bằng chứng. Chọn một test login trong suite của bạn (hoặc giả định). Liệt kê chính xác 5 loại dữ liệu sẽ thu khi nó fail, và với mỗi loại, ghi rõ thời điểm thu (đầu test / lúc fail / cuối test) và điều kiện giữ lại (luôn giữ / chỉ khi fail).
  • Viết hook thu bằng chứng. Viết pseudo-code cho một afterEach/onTestFailure hook: nếu test fail → chụp screenshot, lưu video, pull logcat, đính kèm cả ba vào report. Chú thích rõ chỗ nào phân biệt Android (logcat) và iOS (oslog).
  • Soạn một dòng tóm tắt PR. Viết đúng một dòng tóm tắt cho run giả định: 456 test, 441 pass, 12 fail (đều ở module "Thanh toán"), 3 skip, chạy 14 phút, trên 3 thiết bị. Dòng đó phải giúp PM quyết định release/không release trong 5 giây.
  • Phân tích xu hướng. Cho pass rate 7 ngày liên tiếp: 99%, 98.5%, 99%, 94%, 93.5%, 94%, 93%. Hãy chỉ ra ngày nào là dấu hiệu bất thường cần điều tra và giải thích vì sao nhìn xu hướng lại quan trọng hơn nhìn con số của một ngày.

Tóm tắt

Reporting là nơi công sức QA của bạn được nhìn thấy và tin tưởng. Trên mobile, mỗi test run tối thiểu phải xuất ra: pass/fail/skip count có so sánh, duration từng test, screenshot tại điểm fail, video của test fail, và log native (logcat/oslog) thu theo kiểu streaming. Điểm khác biệt sống còn so với web là bug mobile thường không tái hiện được — nên nếu không thu bằng chứng ngay lúc đó, bạn mất nó mãi mãi, đặc biệt với crash khi app đã chết không còn màn hình để chụp.

Report tốt phục vụ ba tầng người đọc — dev cần chi tiết, lead cần xu hướng, PM cần một dòng kết luận — và giá trị nhất khi nó đến đúng nơi ra quyết định (PR, Slack) chứ không nằm chết trong máy CI. Cuối cùng, hãy nâng cấp từ report tĩnh lên dashboard có history để theo dõi pass rate trend, tách flaky ra khỏi fail thật, và biết chính xác module nào đang vỡ. Nhớ thước đo vàng: một report tốt là report mà dev fix được bug mà không cần hỏi lại bạn câu nào.

Học xong bài này rồi? Tạo tài khoản miễn phí để lưu lại — lần sau vào là biết ngay đang dở ở đâu, và học hết khóa thì có chứng chỉ. Lưu tiến độ của tôi