Blog về kiểm thử ·

Viết báo cáo lỗi thế nào để được nhận: cấu trúc, các bước và những sai lầm thường gặp

Báo cáo lỗi không phải thủ tục giấy tờ. Nó được đọc bởi một người phải tái hiện lỗi trên máy mình, hiểu mức độ tệ đến đâu và quyết định sửa ngay hay để sau bản phát hành. Báo cáo không cho họ những thứ đó sẽ bị trả lại kèm câu hỏi, và cả hai bên cùng mất thời gian.

Một báo cáo gồm những gì

Bộ tối thiểu gần như giống nhau ở mọi nơi: tiêu đề, môi trường, các bước tái hiện, kết quả mong đợi, kết quả thực tế. Mức nghiêm trọng, tệp đính kèm và log là phần thêm — nhưng thiếu năm mục kia thì chưa có báo cáo.

Có một cách tự kiểm tra dễ: đưa báo cáo cho người không biết gì về nhiệm vụ. Nếu họ tái hiện được lỗi mà không hỏi câu nào, báo cáo đã xong.

Tiêu đề: hỏng cái gì và ở đâu

Tiêu đề được đọc trong một danh sách cả trăm dòng, và người ta dựa vào đó để quyết định có mở ra hay không. Vậy nên nó cần hai dữ kiện: chính xác chuyện gì xảy ra và ở chỗ nào. «Giỏ hàng bị hỏng» không có cái nào cả.

Tiêu đề tốt vẫn hiểu được khi bị cắt còn một dòng trong danh sách. Tiêu đề dở thì phải mở ra mới biết nó nói về cái gì.

Lỗi trong đơn hàng

POST /orders tạo đơn khi giỏ hàng trống và trả về 201

Các bước tái hiện: dữ liệu chính xác, không phải kể lại

Một bước là hành động có thể lặp lại y nguyên. «Gửi một giá trị không hợp lệ» thì không lặp lại được: giá trị không hợp lệ là vô số, và một nửa trong đó chạy đúng. Cái cần là đúng giá trị đã làm nó hỏng.

Với API, điều đó nghĩa là phương thức, địa chỉ đầy đủ kèm tham số, phần thân yêu cầu và các tiêu đề nếu chúng có ảnh hưởng. Với giao diện thì là đã bấm gì và gõ gì, đúng từng chữ. Thứ tự cũng quan trọng: lỗi chỉ tái hiện sau khi đăng nhập thì thiếu bước đó sẽ không tái hiện.

1. Mở danh mục
2. Đặt một bộ lọc kỳ lạ
3. Không lọc được gì

1. GET /products?min_price=-500
2. Xem mã phản hồi và số phần tử trong data

Kết quả mong đợi lấy từ yêu cầu

Điểm yếu hay gặp nhất là kết quả mong đợi được nghĩ ra tại chỗ. «Đáng lẽ không nên như vậy» là ý kiến, không phải yêu cầu, và tranh luận về nó có thể kéo dài mãi.

Kết quả mong đợi là một trích dẫn: một dòng trong yêu cầu, một tiêu chí nghiệm thu, một mục tài liệu, hay cách hành xử của phương thức bên cạnh vốn được làm đúng. Nếu chẳng có gì để trích, thì đây chưa phải lỗi mà là câu hỏi cho người phân tích — và nên mở nó đúng như vậy.

Ngược lại, kết quả thực tế được viết không kèm diễn giải: mã phản hồi, phần thân, một con số cụ thể. Không phải «tổng tiền tính sai» mà «trong phản hồi total = 1380 với hai món giá 690 và mã giảm 10%».

Năm sai lầm khiến báo cáo bị trả lại

  1. Hai lỗi trong một báo cáo. Sửa một cái rồi đóng cả phiếu, cái còn lại đi thẳng ra bản phát hành.
  2. Các bước viết theo trí nhớ. Viết một đằng, gửi một nẻo, không tái hiện được.
  3. Nhận xét thay cho sự kiện: «hỏng hết rồi», «chạy tệ lắm». Không rõ phải sửa cái gì.
  4. Thiếu môi trường. Trên máy chủ nào, với người dùng nào, quyền ra sao.
  5. Trùng lặp. Trước khi mở phiếu nên tìm thử — trên bảng thường đã có sẵn một cái.

Ví dụ API bug report hoàn chỉnh

Đây là ví dụ làm việc, không phải form bắt buộc. Nó nối observation với contract và giữ nguyên request chính xác thay vì kể lại theo trí nhớ.

Defect có thể tái hiện khi không có tác giả
Title: POST /orders tạo order cho cart rỗng và trả 201\nEnvironment: QA, build 2026.09.21-3, user qa-buyer-17\nPrecondition: cart của user rỗng\n\nSteps:\n1. Gửi POST /api/v1/orders với Bearer token hợp lệ\n2. Request body: {}\n3. Gửi GET /api/v1/orders\n\nExpected: 422; không tạo order (AC-ORD-04)\nActual: 201; tạo order_id=8412, total=0\nReproducibility: 3/3\nEvidence: request/response HAR, correlation_id=7af2…

Không dán token thật, password, personal data hoặc full production dump. Hãy che secret, dùng synthetic data và chia sẻ log nhạy cảm qua security process đã thống nhất.

Checklist trước khi gửi và retest

Severity mô tả impact, priority mô tả thứ tự business muốn sửa. Thang điểm và owner tùy team nên lý do quan trọng nhất. Sau trạng thái Fixed, QA lặp lại step gốc trên build được nêu và kiểm regression gần nhất thay vì đóng theo comment của developer.

  1. Title có action, kết quả sai và khu vực bị ảnh hưởng.
  2. Có build, environment, role, precondition và test data chính xác.
  3. Expected dẫn tới criterion, contract hoặc quyết định đã ghi.
  4. Actual có fact quan sát được: status, value, time, id và frequency.
  5. Attachment mở được, secret đã che và một report chỉ chứa một defect.
  6. Retest bao phủ scenario gốc, fixed build và regression gần đó.

Ví dụ thực tế: manager khác xem được client

Trong CRM, manager A sở hữu một client nhưng manager B mở được card qua URL trực tiếp. Hãy viết report để developer tái hiện và team đánh giá rủi ro. Câu “xem được client người khác” chưa chỉ ra ranh giới quyền nào bị hỏng.

Từ quan sát tới bằng chứng
  1. Tìm quy tắc access và nguồn expected result.
  2. Chuẩn bị hai account và object có owner rõ ràng.
  3. Lặp lại qua UI và API request trực tiếp.
  4. Lưu bằng chứng an toàn và đánh giá ảnh hưởng.

Phân biệt requirement với giả định

Tìm acceptance criterion nói manager chỉ xem client được giao. Nếu chưa có, hỏi product owner: assignment là giới hạn truy cập hay chỉ là bộ lọc danh sách mặc định? Đừng coi cách hiểu quy trình sales của mình là hợp đồng đã chốt. Ghi số criterion và phiên bản đặc tả trong report; “theo yêu cầu” quá mơ hồ để triage.

Viết bước tái hiện không phụ thuộc tác giả

Tạo user A và B cùng role bằng dữ liệu giả, một client thử nghiệm được giao cho A. Ghi build, môi trường, client id, cách gán owner và URL hoặc API method chính xác. Trước tiên kiểm đối chứng dương: A xem được card. Sau đó B gọi cùng id. Nhờ vậy phân biệt lỗi quyền sở hữu với endpoint hỏng hoặc thực sự được thiết kế công khai.

Chứng minh ở ranh giới hệ thống

Ẩn link không phải access control. Sao chép GET /clients/{id} từ Network và gửi lại bằng session của B; chỉ thử PATCH trong môi trường test được phép. Ghi status, response đã che dữ liệu và việc dữ liệu có đổi không. Nếu API từ chối nhưng UI hiện card cũ từ cache, đó là lỗi khác và nên report riêng.

Ưu tiên và retest

Rò rỉ thông tin liên hệ có thể nghiêm trọng dù hiếm. Escalate qua kênh bảo mật của team, không đính kèm dữ liệu cá nhân thật vào ticket nhiều người xem. Sau fix, lặp request ban đầu, đổi chiều owner, URL trực tiếp, list và export; vá một endpoint không đảm bảo endpoint khác an toàn. Ghi build đã deploy và phạm vi retest.

Khung report
Title: Manager B reads client assigned to A via GET /clients/481\nEnvironment: QA, build 1842; synthetic A and B, same role\nExpected: 403/404 per ACL-07; no client data\nActual: 200 with client name/email; reproduced 3/3\nEvidence: redacted response and correlation_id; no real PII\nScope: GET confirmed; PATCH, list and export not yet checked
Một report mạnh cần gì?

Người khác tái hiện được mà không hỏi thêm, thấy nguồn expected và xem bằng chứng không làm lộ dữ liệu nhạy cảm. Tách sự thật đã xác nhận khỏi giả thuyết về endpoint khác. Retest sau đó phải ghi rõ build thật sự chứa bản sửa.

Tình huống thứ hai: lỗi không tái hiện ổn định

Checkout đôi khi đứng sau bước xác nhận, có thể một lần trong hai mươi lượt. Không nên bỏ qua phát hiện, nhưng cũng chưa đủ bằng chứng để khẳng định nguyên nhân gốc ở payment. Hãy lập report về quan sát, tần suất, bối cảnh và kế hoạch thu thập dữ liệu còn thiếu.

Lưu quan sát trước khi thử tiếp

Ghi thời gian và timezone chính xác, build, browser, account, order id, số tiền và correlation id. Lưu HAR hoặc network exchange nhưng xóa cookies, token và dữ liệu cá nhân. Nêu người dùng nhìn thấy gì, chờ bao lâu và giao dịch có thực sự hoàn tất không. “Bị treo” quá mơ hồ: spinner 12 giây khác 504 sau khi tiền đã bị trừ.

Báo tần suất trung thực

Một lỗi trong hai mươi lần là quan sát 1/20, không chứng minh xác suất đúng 5%. Ghi điều kiện và giữ cả lượt thành công. Đừng thử trên thẻ thật hoặc account dùng chung vì cart history và rate limit thay đổi kết quả. Nếu nghi load, tách nhóm chạy ít và nhiều request song song.

Tách triệu chứng khỏi giả thuyết

Sự thật: request trả 504 nhưng order history hiển thị đã thanh toán. Giả thuyết: response bị mất giữa các service. Không đặt “lỗi queue” vào title khi log chưa xác nhận. So trace thành công và thất bại, latency của dependency và việc message được gửi lại; chia sẻ link log qua kênh được phép.

Định nghĩa hành vi khi kết quả chưa rõ

Sau timeout, client không biết tiền đã bị trừ chưa. Contract cần cho phép đọc status hoặc retry an toàn bằng cùng idempotency key mà không trừ lần hai. Nêu invariant bị phá: order và balance lệch, UI gợi ý trả tiền lại mà không kiểm status, hoặc replay tạo giao dịch kép. “Timeout bug” chung chung che mất rủi ro.

Lên kế hoạch retest và giám sát

Sau fix, lặp dữ liệu và yếu tố làm lỗi dễ xuất hiện; kiểm số giao dịch, log và trạng thái cuối chứ không chỉ UI xanh. Không gặp lỗi trong hai mươi lần không phải chứng minh toán học rằng đã sửa. Ghi số lượt chạy, monitoring ở production và ngưỡng rủi ro team chấp nhận.

Sự thật và giả thuyết
Observed: checkout timeout at 14:03:27 UTC, HTTP 504\nOrder 8412: paid after timeout; UI still shows Pay\nFrequency: 1 failure / 20 attempts on QA build 1842\nEvidence: redacted HAR, correlation_id=7af2, ledger id\nHypothesis: response lost after charge (unconfirmed)\nRisk: retry may cause a second charge\nNext: compare traces; replay with same idempotency key
Khi nào nên tạo defect?

Khi đã có sai lệch quan sát được và rủi ro đáng kể dù bước tái hiện chưa ổn định. Nêu tần suất, bằng chứng, giả thuyết và giới hạn. Nếu bản thân sai lệch còn chưa xác nhận, tạo investigation item với các sự kiện đó thay vì bịa nguyên nhân chắc chắn.

Câu hỏi thường gặp về bug report

Có nên report defect chỉ xảy ra một lần?

Có nếu impact đáng kể và có evidence. Ghi frequency, thời gian, data và log mà không khẳng định tái hiện ổn định. Lỗi payment hiếm vẫn quan trọng hơn margin lệch ổn định.

Ai đặt severity và priority?

Không có quy tắc chung. QA thường đề xuất severity, product hoặc triage đặt priority, nhưng mỗi team có thể khác. Định nghĩa chung và lý do được ghi lại mới là điều quan trọng.

Làm gì khi không có requirement?

Ghi behaviour và risk thành câu hỏi hoặc discovery item, lấy quyết định của product rồi mới xác định expected. Sở thích cá nhân không tự động là defect.

Báo cáo là một tài liệu làm việc, và cách duy nhất để học viết nó là viết vài chục cái: trên lỗi thật, chứ không phải ví dụ bịa ra.

Luyện trên dịch vụ đang chạy Bài tiếp theo

← Tất cả bài viết