CYBERSOFT
Đăng nhập

Độ phủ mã & kiểm thử luồng dữ liệu cho tester: đọc coverage đúng cách qua module tính cước viễn thông (có trắc nghiệm)

Chuyên công nghệViễn thôngNâng caoChuẩn SEO
🗓 1 tháng trước19 phút đọc·👁 530 lượt xem👤 152 người đọc

Bài nâng cao cho tester: phân biệt statement/branch/condition coverage, cách đọc báo cáo coverage để bổ sung đúng ca kiểm thử, khái niệm kiểm thử luồng dữ liệu (define-use), và vì sao '100% test pass' không đồng nghĩa an toàn — minh hoạ qua module tính cước cuộc gọi/data của nhà mạng, có sơ đồ, ticket lỗi thật, FAQ và trắc nghiệm 5 câu.

1. Tóm tắt nhanh & bối cảnh: module tính cước viễn thông

⭐ TL;DR — Độ phủ mã (code coverage) gồm ba mức tester cần phân biệt: statement (dòng lệnh), branch/decision (nhánh rẽ), và condition (điều kiện con trong biểu thức logic) — mỗi mức đo một thứ khác nhau và mức cao hơn không tự động kéo theo mức thấp hơn được phủ đủ. Bài này dùng module tính cước cuộc gọi/data của nhà mạng để minh hoạ: đọc báo cáo coverage để tìm nhánh còn thiếu, khái niệm kiểm thử luồng dữ liệu (data flow testing) qua cặp define-use, và vì sao '100% test pass' không đồng nghĩa an toàn khi coverage vẫn còn lỗ hổng. Có sơ đồ, bảng so sánh, ticket lỗi thật và trắc nghiệm cuối bài.

Bạn là tester trong đội billing của một nhà mạng. Module tinhCuocGoi() tính tiền cuộc gọi/data hàng tháng cho hàng triệu thuê bao — sai một dòng logic, hàng nghìn khách hàng có thể bị tính dư hoặc tính thiếu tiền. Mỗi lần dev build xong, CI/CD tự sinh báo cáo coverage (kiểu Jacoco, Istanbul, SonarQube) và gắn link vào pull request. Bạn không cần tự viết công cụ đo coverage, nhưng bạn CẦN đọc đúng báo cáo đó: biết phân biệt statement, branch, condition; biết chỉ số nào đáng tin, chỉ số nào dễ gây ảo tưởng an toàn; và biết khi nào phải bổ sung ca kiểm thử thủ công nhắm đúng vào lỗ hổng thay vì tin tưởng mù quáng vào con số phần trăm.

javascript
function tinhCuocGoi(soPhut, goiCuoc, laKhachVIP, ngayTrongThang) {
  let cuoc = 0;                                              // DEFINE #1
  if (soPhut <= goiCuoc.phutMienPhi) {
    cuoc = 0;                                                // nhanh THEN - trong goi, khong tinh tien
  } else {
    cuoc = (soPhut - goiCuoc.phutMienPhi) * goiCuoc.donGia;   // DEFINE #2 (nhanh ELSE)
  }
  if (laKhachVIP && ngayTrongThang >= 25) {                  // dieu kien kep (compound condition)
    cuoc = cuoc * 0.8;                                       // USE cuoc + DEFINE #3 - giam gia cuoi thang
  }
  return cuoc;                                                // USE cuoi cung (DU-path ket thuc)
}
📖 Code Coverage: chỉ số đo mức độ mã nguồn được 'chạm tới' khi chạy bộ kiểm thử — nhưng KHÔNG đo việc kết quả có được kiểm tra đúng hay không.

2. Statement coverage — dòng lệnh nào đã chạy, dòng nào chưa

Statement coverage là mức đơn giản nhất: một dòng lệnh được tính là 'đã phủ' nếu nó được thực thi ít nhất một lần trong toàn bộ bộ kiểm thử, bất kể giá trị đầu vào là gì. Với hàm tinhCuocGoi(), chỉ cần một ca gọi trong gói (soPhut nhỏ hơn phutMienPhi) và một ca gọi vượt gói là đủ để mọi DÒNG lệnh — kể cả dòng gán 'cuoc' ở cả hai nhánh if — đều được chạm tới ít nhất một lần. Báo cáo coverage tool thường tô xanh các dòng đã chạy, tô đỏ các dòng chưa từng chạy, giúp tester nhìn nhanh 'code chết' hoặc phần logic hoàn toàn chưa được thử.

Điểm mạnh của statement coverage là đơn giản, dễ hiểu, dễ báo cáo cho quản lý. Nhưng điểm yếu chí mạng: nó KHÔNG phân biệt các trường hợp bên trong cùng một điều kiện. Dòng if(soPhut <= goiCuoc.phutMienPhi) chỉ cần chạy MỘT lần, dù nhánh true hay nhánh false, là được tính 'đã phủ' — dòng if đó không đòi hỏi cả hai khả năng đều được thử. Đây chính là lý do một module đạt 96% statement coverage (như trong dashboard ở chương 9) vẫn có thể ẩn giấu một nhánh nghiệp vụ quan trọng chưa từng chạy, như nhánh giảm giá cuối tháng cho khách VIP.

📖 Statement Coverage: tỉ lệ phần trăm DÒNG LỆNH trong mã nguồn đã được thực thi ít nhất một lần bởi bộ test.

3. Branch/Decision coverage — nhánh rẽ nào đã được đi qua

Branch coverage (còn gọi decision coverage) khắt khe hơn statement coverage một bậc: mỗi ĐIỂM RẼ NHÁNH (if, else, switch-case, vòng lặp có điều kiện...) phải được đi qua ở CẢ HAI khả năng — đúng và sai — chứ không chỉ một trong hai. Với if(soPhut <= goiCuoc.phutMienPhi), branch coverage đòi hỏi ít nhất một ca cho nhánh true (gọi trong gói) VÀ ít nhất một ca cho nhánh false (gọi vượt gói). Với if(laKhachVIP && ngayTrongThang >= 25), branch coverage đòi hỏi cả nhánh true (được giảm giá) và nhánh false (không được giảm giá) đều từng chạy — đây chính là nhánh dễ bị bỏ sót nhất trong thực tế vì nó chỉ đúng vào cuối tháng, một khung thời gian hẹp mà đội test hay quên chủ động mô phỏng.

So sánh 3 mức độ phủ mã trên hàm tinhCuocGoi Loại độ phủĐo cái gìVí dụ trên tinhCuocGoiRủi ro nếu chỉ dừng ở đâyStatement coverageMỗi DÒNG lệnh được thực thi ≥ 1 lần1 ca gọi ngắn + 1 ca gọi dài đã chạy hết các dòng gán 'cuoc'100% dòng chạy nhưng chưa chắc đủ tổ hợp nhánh rẽBranch/Decision coverageMỗi NHÁNH true/false của mỗi if được đi qua ≥ 1 lầnCa cho IF#1 đúng, IF#1 sai, IF#2 đúng, IF#2 saiNhánh 'đúng' của IF#2 (giảm giá) có thể chưa từng chạyCondition coverageMỗi ĐIỀU KIỆN CON trong biểu thức logic nhận cả true/falselaKhachVIP=true/false và ngayTrongThang≥25=true/false được thử riêngPhủ đủ điều kiện con chưa chắc phủ đủ tổ hợp NHÁNH kết quảBa mức không thay thế nhau: 100% statement không suy ra 100% branch, và 100% branch không suy ra 100% condition.
Bảng so sánh statement, branch/decision và condition coverage trên hàm tính cước
📖 Branch Coverage: tỉ lệ phần trăm các NHÁNH RẼ (true/false của mỗi điều kiện if/else, switch...) đã được đi qua ít nhất một lần.

4. Condition coverage — điều kiện kép & bẫy short-circuit

Khi một điều kiện là biểu thức KÉP như laKhachVIP && ngayTrongThang >= 25, branch coverage chỉ quan tâm KẾT QUẢ CHUNG của cả biểu thức (true hoặc false), không quan tâm từng vế riêng lẻ. Condition coverage đi sâu hơn: mỗi ĐIỀU KIỆN CON (ở đây là laKhachVIP và ngayTrongThang >= 25) phải nhận CẢ true lẫn false ở các ca test khác nhau, độc lập với kết quả chung. Điều này quan trọng vì hai ca test có thể khiến biểu thức tổng đủ true/false (branch coverage 100%) nhưng một điều kiện con cụ thể vẫn chưa bao giờ được thử theo cả hai hướng — như bạn sẽ thấy rõ trong tình huống 2 ở chương 8.

Có một bẫy riêng cần tester nhớ: hầu hết ngôn ngữ lập trình (JavaScript, Java, Python...) dùng SHORT-CIRCUIT EVALUATION cho toán tử &&. Nghĩa là nếu vế trái (laKhachVIP) đã là false, ngôn ngữ sẽ KHÔNG BAO GIỜ đánh giá vế phải (ngayTrongThang >= 25) nữa — vế phải bị 'bỏ qua' hoàn toàn về mặt thực thi. Vì vậy một ca test với laKhachVIP=false không hề cung cấp bất kỳ thông tin gì về việc điều kiện ngày tháng hoạt động đúng hay sai; muốn thực sự thử vế phải, bắt buộc phải có ca với laKhachVIP=true. Hiểu rõ short-circuit giúp tester không nhầm lẫn 'đã chạy qua dòng' với 'đã thực sự đánh giá điều kiện'.

🔒

Nội dung bị khoá

Bạn đang xem bản xem trước. Đăng nhập để mở khoá toàn bộ bài viết và tất cả tài liệu Tester/QA.

Đã xem 24% nội dung
  • Đọc trọn vẹn mọi bài viết
  • Lưu bài & ghi chú cá nhân
  • Theo dõi tiến độ đã đọc
  • Luyện phỏng vấn, ISTQB, Mock
Đăng nhập để đọc tiếp

Chưa có mã? Lấy mã qua Fanpage / Zalo CyberSoft.

0

💬 Bình luận (0)

Bạn có thể đọc mọi bình luận. Đăng nhập để bình luận

Chưa có bình luận nào. Hãy là người đầu tiên!