Menu
ESC

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

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

Đang tải...

Test Execution & Status Tracking

Software Testing Fundamentals Bài 29/60

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

Hãy tưởng tượng bạn đã bỏ ra hai tuần để viết 400 test case tuyệt đẹp. Chúng đầy đủ, rõ ràng, được review kỹ càng. Nhưng rồi đến ngày cuối sprint, sếp hỏi bạn: "Chức năng thanh toán đã test xong chưa? Có gì đang chặn không? Tỷ lệ pass là bao nhiêu?" — và bạn ú ớ không trả lời được ngay, phải mở file Excel ra dò từng dòng suốt mười lăm phút. Lúc đó, mọi công sức thiết kế test case của bạn gần như vô nghĩa. Bởi vì một bộ test case, dù hoàn hảo đến đâu, cũng chỉ là "ý định". Còn test execution — quá trình thực sự chạy chúng và ghi lại kết quả — mới là thứ biến ý định thành thông tin có giá trị cho cả dự án.

Test execution và status tracking là "trái tim đập" của một chu kỳ kiểm thử. Đây là giai đoạn mà tester dành phần lớn thời gian, và cũng là nơi tạo ra dữ liệu để trả lời câu hỏi quan trọng nhất trong QA: "Sản phẩm này đã đủ tốt để release chưa?" Nếu bạn tracking cẩu thả, cả team sẽ ra quyết định release dựa trên cảm tính. Nếu bạn tracking chuẩn, mỗi con số bạn đưa ra đều là một mảnh bằng chứng khách quan.

Trong bài này, chúng ta sẽ đi sâu vào cách một test case chuyển đổi giữa các trạng thái sau khi được thực thi, cách bạn theo dõi tiến độ execution theo thời gian thực, và cách phân biệt những trạng thái dễ gây nhầm lẫn như BlockedFail. Đây là kỹ năng nền tảng mà bất kỳ tester nào cũng phải thành thạo trước khi nói đến chuyện báo cáo hay ra quyết định — những chủ đề của các bài sau.

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

Test execution là gì?

Test execution là hành động chạy từng test case theo đúng các bước (steps) đã thiết kế, quan sát kết quả thực tế (actual result), so sánh với kết quả mong đợi (expected result), rồi ghi nhận một trạng thái (status) cho test case đó. Nghe đơn giản, nhưng bản chất của execution là kỷ luật: chạy đúng bước, ghi trung thực, không "đoán" kết quả, không bỏ qua bước nào chỉ vì "chắc là nó chạy được".

Một chu kỳ execution thường gắn với một khái niệm gọi là test run (hay test cycle) — tức là một lần chạy toàn bộ hoặc một phần bộ test case trên một phiên bản build cụ thể. Ví dụ, khi dev bàn giao build v2.3.0, bạn tạo một test run mới và bắt đầu execute. Khi build v2.3.1 ra đời với các bug đã fix, bạn tạo test run khác. Việc tách theo test run giúp bạn so sánh chất lượng giữa các build và không lẫn lộn kết quả cũ với kết quả mới.

Các trạng thái của test case sau khi execute

Đây là phần cốt lõi nhất. Sau khi chạy một test case, nó sẽ rơi vào một trong các trạng thái sau:

Not Run (Chưa chạy) — Test case đã có trong test run nhưng bạn chưa thực thi. Đây là trạng thái mặc định khi bạn khởi tạo một test run. Số lượng Not Run cho biết còn bao nhiêu việc phải làm, là chỉ số trực tiếp phản ánh tiến độ execution.

Pass (Đạt) — Bạn chạy đủ các bước, và actual result khớp hoàn toàn với expected result. Lưu ý: "khớp một phần" không phải là Pass. Nếu 9/10 bước đúng nhưng bước cuối sai, đó là Fail, không phải "Pass với ghi chú".

Fail (Không đạt) — Actual result khác với expected result. Đây là lúc test case "bắt" được lỗi. Nguyên tắc bất di bất dịch: mỗi test case Fail phải được link tới một bug report (defect ID). Không có defect ID đi kèm, một trạng thái Fail gần như vô giá trị — vì người đọc report không biết lỗi đó là gì, ai đang xử lý, và mức độ nghiêm trọng ra sao.

Blocked (Bị chặn) — Bạn không thể thực thi test case vì một lý do nằm ngoài bản thân test case đó. Ví dụ: chức năng đăng nhập bị lỗi nặng nên bạn không vào được màn hình để test tính năng bên trong; hoặc môi trường test bị sập; hoặc một tính năng phụ thuộc chưa được dev bàn giao. Điểm mấu chốt: Blocked không có nghĩa là test case này pass hay fail — bạn đơn giản là chưa có cơ hội biết. Đây là trạng thái tester Việt Nam hay dùng sai nhất, nên chúng ta sẽ mổ xẻ kỹ ở phần dưới.

Skipped / Not Applicable (Bỏ qua / Không áp dụng) — Test case được cố ý không chạy trong test run này. Có thể vì nó thuộc tính năng ngoài phạm vi sprint, hoặc không áp dụng cho cấu hình đang test (ví dụ test case dành riêng cho iOS khi bạn đang test bản Android). Khác với Blocked ở chỗ: Skipped là quyết định có chủ đích, còn Blocked là bị buộc phải dừng.

In Progress / Retest (Đang chạy / Chờ test lại) — Một số công cụ có thêm trạng thái trung gian. In Progress dùng cho test case dài chạy qua nhiều phiên. Retest đánh dấu những test case từng Fail, nay bug đã được fix và đang chờ bạn verify lại.

Phân biệt Blocked và Fail — ranh giới quan trọng nhất

Rất nhiều tester mới đánh dấu Fail cho mọi thứ không chạy được, khiến báo cáo bị thổi phồng sai lệch. Hãy nhớ nguyên tắc: Fail = test case này chạy được và cho kết quả sai. Blocked = test case này không chạy được để mà biết đúng hay sai.

Ví dụ: bạn muốn test "thêm sản phẩm vào giỏ hàng", nhưng nút "Đăng nhập" bị crash nên bạn không vào được tài khoản. Test case "thêm vào giỏ" ở đây phải là Blocked, không phải Fail — vì lỗi nằm ở đăng nhập, không phải ở logic giỏ hàng. Nếu bạn đánh Fail, report sẽ nói dối rằng "chức năng giỏ hàng bị lỗi", trong khi thực tế bạn chưa hề chạm tới nó.

Traceability — mọi kết quả phải truy vết được

Mỗi lần ghi status, bạn nên đính kèm: phiên bản build đang test, môi trường (staging/production-like), người execute, thời điểm, và với Fail thì có link bug. Bộ thông tin này gọi là execution evidence. Khi có tranh cãi "sao lúc đó pass mà giờ lại lỗi?", chính evidence này cứu bạn.

Tình huống thực tế

Tình huống 1: Sàn TMĐT và cái bẫy "Blocked bị đếm nhầm là Fail"

Một công ty thương mại điện tử tại TP.HCM (giả định tên là ShopViet) chuẩn bị release tính năng thanh toán qua ví điện tử cho chiến dịch 6/6. Đội QA có 5 người, cùng execute một test run gồm 620 test case trên build v4.1.0. Đến chiều ngày thứ hai của chu kỳ, dashboard hiển thị: 180 Pass, 140 Fail, 300 Not Run. Team lead hoảng loạn báo lên PM rằng chất lượng build "thảm họa", đề nghị hoãn release.

Nhưng khi ngồi rà lại từng test case Fail, họ phát hiện: 120 trong số 140 "Fail" thực chất là do cổng thanh toán trên môi trường staging bị sập từ 10 giờ sáng. Các tester, vì thói quen, cứ thấy không hoàn thành được là đánh Fail. Con số thật sau khi phân loại lại: chỉ 20 Fail thực sự (lỗi logic), còn 120 phải chuyển sang Blocked. Sau khi môi trường được khôi phục lúc 3 giờ chiều, 120 case Blocked đó chạy lại thì 115 Pass.

Bài học: Con số Fail và Blocked kể hai câu chuyện hoàn toàn khác nhau. Fail cao nghĩa là code có vấn đề — trách nhiệm thuộc dev. Blocked cao nghĩa là môi trường hoặc dependency có vấn đề — trách nhiệm thuộc DevOps/hạ tầng. Đánh sai trạng thái không chỉ làm PM ra quyết định sai, mà còn đổ oan cho nhầm người. Kể từ đó, ShopViet đặt quy tắc: bất kỳ test case Blocked nào cũng phải ghi rõ lý do block trong ô comment.

Tình huống 2: Startup fintech và "báo cáo tiến độ láo" vì không tracking theo build

Một startup fintech ở Hà Nội (giả định là PayMoi) có một tester junior tên Linh execute một bộ 250 test case trong ba ngày. Vấn đề: trong ba ngày đó, dev deploy tới 4 build khác nhau, nhưng Linh chỉ dùng một file Excel duy nhất, cứ chạy tới đâu tô màu tới đó, và mỗi khi có build mới, bạn ấy sửa đè kết quả cũ. Đến cuối, Linh báo cáo "240/250 pass".

Khi release, khách hàng gặp lỗi ngay ở tính năng chuyển khoản. Điều tra ra mới thấy: test case chuyển khoản được Linh đánh Pass ở build 2, nhưng build 4 (bản thực sự release) đã sửa một đoạn code liên quan làm hỏng tính năng này — mà không ai chạy lại. Báo cáo "240 pass" là con số Frankenstein, ghép từ nhiều build, không phản ánh chất lượng của bất kỳ build nào cụ thể.

Bài học: Một kết quả Pass chỉ có giá trị gắn với một build cụ thể. Khi có build mới, bạn không được "kế thừa" kết quả cũ một cách vô tội vạ — ít nhất phải xác định vùng bị ảnh hưởng và chạy lại. Đây chính là lý do các công cụ như TestRail, Xray, Zephyr đều tổ chức execution theo từng test run gắn với build, chứ không cho tô đè lên nhau. Sau sự cố, PayMoi chuyển sang TestRail và bắt buộc mỗi test run phải khai báo build number.

Tình huống 3: Team outsource và bảng "burndown" execution cứu deadline

Một công ty gia công phần mềm ở Đà Nẵng làm dự án cho khách Nhật, cam kết execute xong 1.500 test case trong 8 ngày. QA lead thiết lập một chỉ số theo dõi đơn giản mỗi cuối ngày: số test case đã execute (Pass + Fail + Blocked) so với đường mục tiêu lý tưởng (mỗi ngày cần xong ~188 case). Đến ngày thứ 3, đường thực tế tụt xa dưới đường lý tưởng: mới execute 400/564 case cần thiết. Nhìn dữ liệu, lead phát hiện nguyên nhân là 60% thời gian tester bị "ngốn" vào việc điều tra và log bug cho một module lỗi nặng.

Nhờ thấy sớm qua tracking, lead kịp điều 2 người từ module ổn định sang hỗ trợ, đồng thời báo khách xin ưu tiên fix module lỗi. Kết quả: về đích đúng hạn với 1.500 case execute xong.

Bài học: Status tracking không chỉ để báo cáo cuối kỳ, mà là công cụ điều hành trong lúc chạy. Nếu bạn chỉ nhìn kết quả vào ngày cuối, bạn chỉ có thể "chứng kiến thất bại". Nếu bạn theo dõi tốc độ execution hằng ngày (velocity), bạn có thể can thiệp khi còn kịp.

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

Dưới đây là quy trình execution và tracking chuẩn bạn có thể áp dụng ngay:

Bước 1 — Chuẩn bị test run. Xác nhận build number, môi trường, và bộ test case đưa vào run. Đặt tên test run rõ ràng, ví dụ: Payment_v4.1.0_Staging_20260627. Toàn bộ test case khởi tạo ở trạng thái Not Run.

Bước 2 — Kiểm tra điều kiện tiên quyết (precondition). Trước khi chạy, đảm bảo môi trường ổn định, test data đã sẵn sàng, tài khoản đăng nhập hoạt động. Bỏ qua bước này là nguyên nhân số một sinh ra hàng loạt Blocked/Fail giả.

Bước 3 — Execute từng test case. Chạy đúng thứ tự các bước, quan sát và ghi lại actual result. So sánh với expected result rồi gán status. Đừng chạy nhảy cóc bỏ bước.

Bước 4 — Xử lý khi Fail. Nếu Fail, log bug ngay với đầy đủ steps to reproduce, screenshot/video, build, môi trường. Sau đó link defect ID vào test case. Đừng để "log bug sau" — bạn sẽ quên chi tiết.

Bước 5 — Xử lý khi Blocked. Ghi rõ lý do bị chặn và, nếu có, blocker ID (bug hoặc ticket hạ tầng đang chặn). Đánh dấu để quay lại khi blocker được giải quyết.

Bước 6 — Cập nhật tiến độ hằng ngày. Cuối mỗi ngày, chốt số: bao nhiêu Pass / Fail / Blocked / Not Run, tốc độ so với kế hoạch. Đây là dữ liệu để bạn (và lead) điều hành.

Bước 7 — Retest sau khi bug được fix. Khi build mới có bug đã fix, chuyển các case liên quan sang trạng thái Retest, chạy lại, cập nhật status mới trong test run của build mới — không sửa đè lên run cũ.

Bước 8 — Chốt test run. Khi mọi case đã có status (không còn Not Run trừ phần cố ý Skipped), test run được đóng lại, sẵn sàng làm đầu vào cho báo cáo.

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

  • Đánh Fail cho mọi thứ không chạy được. Như đã phân tích, hãy phân biệt Fail (kết quả sai) và Blocked (không chạy được để biết). Mẹo: tự hỏi "lỗi này nằm trong phạm vi test case, hay ngoài nó?" — ngoài thì Blocked.
  • Fail mà không link bug. Một Fail "trần trụi" không giúp ai cả. Luôn gắn defect ID. Nhiều công cụ cho phép tạo bug và link ngay trong màn hình execution.
  • Để test case treo ở Not Run mà không giải thích. Cuối kỳ còn Not Run mà không rõ lý do khiến người đọc report tưởng bạn làm chưa xong. Nếu cố ý không chạy, hãy đổi sang Skipped kèm lý do.
  • Kế thừa kết quả pass giữa các build một cách bừa bãi. Pass ở build cũ không đảm bảo pass ở build mới. Xác định vùng ảnh hưởng và retest.
  • Chỉ ghi Pass/Fail mà bỏ actual result. Với case Pass thì có thể chấp nhận, nhưng với Fail, thiếu actual result khiến không ai tái hiện được. Luôn ghi cái bạn thực sự thấy.
  • Không ghi evidence (build, môi trường, thời điểm). Khi có tranh cãi, evidence là bằng chứng bảo vệ bạn. Mẹo: cấu hình công cụ tự động gắn các thông tin này vào mỗi lần execute.
  • Mẹo chọn công cụ: Nếu dự án nhỏ, một Google Sheet có cột Status với data validation (dropdown Pass/Fail/Blocked/Not Run) và conditional formatting tô màu là đủ. Dự án lớn nên dùng TestRail, Xray (trong Jira), hoặc Zephyr để tự động thống kê và tránh lỗi tô đè.

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

  • Phân loại trạng thái. Với mỗi tình huống sau, xác định status đúng (Pass/Fail/Blocked/Skipped): (a) Bạn test "đổi mật khẩu", nhập đúng và hệ thống báo đổi thành công đúng như mong đợi. (b) Bạn muốn test "xuất hóa đơn PDF" nhưng server sinh PDF đang bảo trì. (c) Bạn test "tìm kiếm sản phẩm", kết quả trả về thiếu 3 sản phẩm lẽ ra phải có. (d) Test case dành cho trình duyệt Safari, nhưng sprint này chỉ test Chrome.
  • Thiết kế mini tracking sheet. Tạo một Google Sheet với các cột: Test Case ID, Tên, Build, Môi trường, Status (dropdown), Actual Result, Defect ID, Người test, Thời gian. Thêm conditional formatting: Pass màu xanh, Fail màu đỏ, Blocked màu vàng, Not Run xám. Nhập thử 10 dòng dữ liệu.
  • Viết công thức tổng hợp. Trên sheet ở bài 2, dùng hàm COUNTIF để tự động đếm số Pass, Fail, Blocked, Not Run, và tính tỷ lệ Pass = Pass / (Pass + Fail).
  • Tình huống điều hành. Bạn có 500 test case, kế hoạch 5 ngày. Hết ngày 2 bạn mới execute 120 case, trong đó 40 Blocked vì môi trường chập chờn. Viết 3 gạch đầu dòng bạn sẽ báo cáo cho lead và đề xuất hành động.

Tóm tắt

Test execution là giai đoạn biến những test case "trên giấy" thành thông tin thực về chất lượng sản phẩm, và status tracking là cách bạn ghi lại thông tin đó một cách khách quan, truy vết được. Bốn trạng thái nền tảng — Not Run, Pass, Fail, Blocked (cùng Skipped và Retest) — mỗi cái kể một câu chuyện riêng, và việc gán đúng trạng thái là kỹ năng phân biệt quan trọng bậc nhất của một tester.

Ba nguyên tắc bạn cần khắc cốt: (1) Fail phải link bug, nếu không thì vô nghĩa; (2) Blocked không phải Fail — đừng đổ oan cho code khi lỗi nằm ở môi trường; (3) kết quả luôn gắn với một build cụ thể, đừng kế thừa Pass bừa bãi giữa các build. Cuối cùng, hãy tracking mỗi ngày như một công cụ điều hành, không phải chỉ là thủ tục cuối kỳ — vì dữ liệu execution kịp thời chính là thứ giúp cả team ra quyết định release đúng đắn, chủ đề mà các bài về báo cáo và release sẽ tiếp tục đào sâu.