Kiểm thử phần mềm là gì và vì sao bốn test case đạt vẫn chưa đủ
Xem thửSáng thứ Bảy, ứng dụng đặt đồ uống của Cà Phê Chú Tư mở đợt khuyến mãi. Mã CHUTU10 giảm 10% tổng đơn, tối đa 15.000 đồng, áp dụng cho đơn từ 50.000 đồng trở lên. Tối thứ Sáu, bạn Bình (tester của quán) đã nhập thử bốn đơn với mã này: 40.000, 50.000, 100.000 và 150.000 đồng. Cả bốn đơn đều ra đúng số tiền. Bình ghi "Đạt" vào bảng theo dõi và nhóm phát hành phiên bản 2.3.
Hết ngày thứ Bảy, hệ thống ghi nhận 312 đơn dùng mã, trong đó 74 đơn có giá trên 150.000 đồng. Chú Tư mở báo cáo và thấy tiền giảm giá cao hơn dự tính: mỗi đơn lớn bị giảm nhiều hơn quy định, tổng cộng quán "tặng nhầm" khoảng 518.000 đồng (số liệu minh họa).
Trước khi đọc tiếp, hãy lấy giấy bút và trả lời: bốn test case đều đạt, vậy nhóm đã kiểm thử sai ở đâu, hay thật ra không sai? Và trong ba thứ sau, thứ nào đáng gọi là "bug": việc bạn An (lập trình viên) đọc yêu cầu, dòng code tính giảm giá, hay con số hiện trên màn hình của khách?
Sau bài này, bạn có thể
- Nêu ba mục tiêu của kiểm thử: tìm lỗi, cung cấp thông tin để nhóm ra quyết định, giảm rủi ro.
- Gọi đúng tên ba mắt xích sai sót (error), lỗi (defect) và sự cố (failure) trong một tình huống cụ thể.
- Phân biệt kiểm thử với gỡ lỗi (debugging) theo người làm, câu hỏi và sản phẩm đầu ra.
- Giải thích vì sao "mọi test case đều đạt" chưa chứng minh được phần mềm hết lỗi.
Cần biết trước: bạn đã gặp khái niệm vòng đời phát triển phần mềm (SDLC) ở chương 1. Bạn không cần biết lập trình: đoạn code ngắn trong bài chỉ để đọc hiểu.
Bằng chứng: bốn lần thử đạt, lần thứ năm thì không
Quy định của mã CHUTU10 là: đơn dưới 50.000 đồng không được giảm, còn lại giảm 10% nhưng không quá 15.000 đồng. Sau khi sự cố xảy ra, Bình nhập thêm một đơn 200.000 đồng và ghi lại kết quả cả năm đơn:
| Giá trị đơn | Giảm đúng quy định | Giảm mà app hiển thị | Kết luận |
|---|---|---|---|
| 40.000 | 0 | 0 | Đạt |
| 50.000 | 5.000 | 5.000 | Đạt |
| 100.000 | 10.000 | 10.000 | Đạt |
| 150.000 | 15.000 | 15.000 | Đạt |
| 200.000 | 15.000 | 20.000 | Không đạt, khách trả 180.000 thay vì 185.000 |
Điểm đáng chú ý: lỗi chỉ lộ ra khi 10% của đơn vượt 15.000 đồng, tức đơn trên 150.000 đồng. Cả bốn giá trị Bình chọn tối hôm trước đều nằm dưới ngưỡng đó. Bình không làm sai quy trình, bộ dữ liệu thử chỉ chưa chạm vào chỗ có lỗi.
Đây là hàm tính giảm giá mà An đã viết, kèm bản đã sửa (dùng JavaScript, bạn chỉ cần đọc hiểu):
// Bản có lỗi
function calcDiscount(subtotal) {
if (subtotal < 50000) return 0;
return subtotal * 0.1;
}
// Bản đã sửa
function calcDiscountFixed(subtotal) {
if (subtotal < 50000) return 0;
return Math.min(subtotal * 0.1, 15000);
}
| Dòng code | Máy làm gì | Vì sao có dòng này |
|---|---|---|
if (subtotal < 50000) return 0; | Đơn dưới 50.000 thì trả về mức giảm 0 và dừng hàm | Thể hiện điều kiện "đơn từ 50.000 đồng" |
return subtotal * 0.1; | Trả về đúng 10% giá trị đơn, không giới hạn trên | Thể hiện "giảm 10%", nhưng thiếu vế "tối đa 15.000" |
Math.min(subtotal * 0.1, 15000) | Lấy số nhỏ hơn giữa 10% đơn và 15.000 | Chặn mức giảm ở 15.000, đúng quy định |
Mình đã chạy cả hai hàm với năm giá trị trên: bản có lỗi trả về 20.000 cho đơn 200.000, bản đã sửa trả về 15.000, bốn đơn còn lại hai bản cho kết quả giống nhau. Vì vậy bốn test case đầu không thể phân biệt hai bản.
Mô hình tư duy 1: một chuỗi ba mắt xích, không phải một chữ "bug"
Đời thường, người ta gọi cả ba thứ ở câu hỏi mở đầu là "bug". Trong kiểm thử, tiêu chuẩn của ISTQB (tổ chức đặt bộ thuật ngữ và chứng chỉ kiểm thử phổ biến trên thế giới) tách chúng thành chuỗi nhân quả: con người mắc sai sót (error, còn gọi là mistake), sai sót tạo ra lỗi (defect, còn gọi là bug hoặc fault) trong sản phẩm, và khi phần chứa lỗi được chạy trong điều kiện phù hợp thì có thể xảy ra sự cố (failure).
| Mắt xích | Nằm ở đâu | Ai nhìn thấy | Trong ví dụ của Cà Phê Chú Tư |
|---|---|---|---|
| Sai sót (error) | Trong đầu người làm | Thường không ai thấy | An đọc yêu cầu, nhớ "giảm 10%" nhưng bỏ sót "tối đa 15.000" |
| Lỗi (defect) | Trong sản phẩm: code, tài liệu, cấu hình | Người đọc code hoặc tài liệu | Dòng return subtotal * 0.1; thiếu giới hạn |
| Sự cố (failure) | Lúc chạy, trên màn hình hoặc dữ liệu | Tester và khách hàng | Đơn 200.000 bị giảm 20.000 thay vì 15.000 |
Ba điều rút ra từ chuỗi này:
- Tester thường nhìn thấy sự cố trước, chưa thấy lỗi. Bình chỉ biết con số trên màn hình sai. Dòng code nào gây ra thì An phải tìm.
- Lỗi có thể nằm im mà không gây sự cố. Với đơn dưới 150.000 đồng, dòng code sai vẫn chạy nhưng cho kết quả đúng. ISTQB mô tả: có lỗi luôn gây sự cố khi chạy, có lỗi chỉ gây sự cố trong hoàn cảnh nhất định, có lỗi không bao giờ gây sự cố.
- Lỗi không chỉ có trong code. Một dòng yêu cầu viết mơ hồ, một test script sai cũng là lỗi. Ngược lại, không phải sự cố nào cũng do lỗi: app chậm vì mất sóng 4G là điều kiện môi trường, không phải dòng code sai.
Hãy bấm Bước tiếp trong mô phỏng bên dưới để xem chuỗi này chạy theo thời gian, rồi thử nút đổi biến thể để so sánh hai cách thử của Bình.
Đang tải Animation…
Mô hình tư duy 2: kiểm thử để làm gì?
Nhiều người mới nghĩ kiểm thử chỉ để "tìm bug". Đó là một mục tiêu, nhưng không phải tất cả. Ba mục tiêu cốt lõi cho người mới:
| Mục tiêu | Câu hỏi mà kiểm thử trả lời | Ví dụ ở Cà Phê Chú Tư |
|---|---|---|
| Tìm lỗi | Phần mềm có làm điều không nên làm, hoặc không làm điều nên làm không? | Thử đơn 200.000 và phát hiện mức giảm vượt quy định |
| Cung cấp thông tin để ra quyết định | Nhóm có đủ dữ kiện để quyết định phát hành, hoãn hay sửa tiếp không? | Báo cáo cho chú Tư: đã chạy 28 test case, 26 đạt, 2 lỗi, trong đó 1 lỗi sai tiền |
| Giảm rủi ro | Những chỗ nào nếu hỏng sẽ gây thiệt hại lớn, và ta đã kiểm tra chúng chưa? | Dồn thời gian vào thanh toán và mã giảm giá trước màn hình giới thiệu quán |
ISTQB còn liệt kê thêm các mục tiêu như xác nhận yêu cầu đã được đáp ứng hoặc xây dựng sự tin tưởng vào chất lượng. Ba mục tiêu trên đã đủ để bạn hiểu vì sao tester không "chỉ bấm thử".
Mục tiêu thứ hai thường bị bỏ quên. Giả sử chú Tư hỏi: "Ra bản 2.3 được chưa?". Tester không có quyền quyết định thay chú, nhưng có trách nhiệm đưa thông tin thật: đã kiểm tra những gì, chưa kiểm tra gì, tìm thấy gì, mức ảnh hưởng ra sao. Câu trả lời "đạt hết rồi, chắc ổn" là thông tin nghèo. Câu trả lời "đã thử đơn từ 40.000 đến 150.000, chưa thử đơn trên 150.000, chưa thử mã hết hạn" cho chú một bức tranh để quyết định.
Mục tiêu thứ ba cho ta lý do chọn việc trước, việc sau. Rủi ro có thể hiểu là khả năng xảy ra nhân với hậu quả. Một lỗi sai tiền ở màn hình thanh toán (hậu quả: quán mất tiền, khách mất lòng tin) nặng hơn nhiều lỗi logo lệch vài điểm ảnh, dù cả hai đều là lỗi. Ví dụ số liệu minh họa: 74 đơn nhân với trung bình 7.000 đồng lệch mỗi đơn là 518.000 đồng trong một ngày, còn logo lệch không làm quán mất đồng nào.
Mô hình tư duy 3: kiểm thử khác gỡ lỗi, và không chứng minh hết lỗi
Hai việc này hay bị gộp thành một vì thường do cùng một nhóm người nói chuyện với nhau. Thực tế, chúng là hai hoạt động riêng:
| Tiêu chí | Kiểm thử (testing) | Gỡ lỗi (debugging) |
|---|---|---|
| Ai làm chính | Tester | Lập trình viên |
| Câu hỏi | Phần mềm có hành xử đúng không? Sai ở đâu, khi nào? | Vì sao nó sai? Dòng code nào gây ra? |
| Đầu ra | Kết quả chạy test, báo cáo sự cố | Bản sửa code |
| Trong ví dụ | Bình thấy đơn 200.000 bị giảm 20.000 | An tìm ra thiếu Math.min và thêm vào |
Theo ISTQB, quy trình gỡ lỗi khi kiểm thử động gây ra sự cố gồm ba việc: tái hiện sự cố, chẩn đoán (tìm lỗi), sửa lỗi. Sau đó đến lượt kiểm thử quay lại: kiểm thử xác nhận (confirmation testing) chạy lại đúng test đã thất bại để xem lỗi đã hết chưa, và kiểm thử hồi quy (regression testing) chạy lại các test khác để xem bản sửa có làm hỏng chỗ khác không. ISTQB khuyến nghị kiểm thử xác nhận nên do chính người đã chạy test lúc đầu thực hiện.
Sơ đồ dưới đây gom vòng đó lại.
Đang tải sơ đồ…
Cách đọc hình: đi từ trên xuống. Khối cam là chỗ so sánh kết quả thực tế với kết quả mong đợi, việc của tester. Nhánh đỏ là lúc có sự cố; từ đó trách nhiệm chuyển sang lập trình viên (khối tím đầu tiên) rồi quay lại tester (khối tím thứ hai). Nhánh "Yes" dừng ngay ở "Test passed", và dừng ở đó là có chủ ý: kết quả đạt chỉ nói rằng sự cố chưa xuất hiện với dữ liệu này.
Điều đó dẫn tới điểm quan trọng nhất của bài. Bốn đơn đầu đạt không chứng minh được phần mềm hết lỗi, vì ta mới thử bốn giá trị trong vô số giá trị có thể nhập. Kiểm thử chỉ cho thấy có lỗi hoặc chưa thấy lỗi trong phạm vi đã thử. Cách nói trung thực trong báo cáo là: "Không phát hiện sự cố với các đơn từ 40.000 đến 150.000 đồng; chưa kiểm tra đơn trên 150.000 đồng." Bài sau sẽ gọi đây là nguyên tắc thứ nhất trong bảy nguyên tắc kiểm thử.
Kiểm thử cũng không chỉ là chạy phần mềm. ISTQB phân biệt kiểm thử động (dynamic testing), tức chạy phần mềm như Bình làm, và kiểm thử tĩnh (static testing), tức xem xét tài liệu hoặc code mà không chạy. Nếu Bình đọc yêu cầu CHUTU10 và hỏi "10% tính trên tổng trước hay sau phí giao hàng, và có tối đa không?", cô đã tìm lỗi trong tài liệu từ trước khi An viết dòng code nào. Với kiểm thử tĩnh, không có sự cố để tái hiện, vì lỗi được phát hiện trực tiếp.
Hiểu lầm thường gặp
- "Tester làm cho phần mềm hết lỗi." Sai ở chỗ nhầm vai. Tester tìm và báo sự cố, cung cấp thông tin; việc tìm nguyên nhân và sửa là gỡ lỗi của lập trình viên. Hơn nữa không ai bảo đảm được hết lỗi.
- "Mọi test case đạt nghĩa là không còn bug." Sai ở chỗ coi bộ test là toàn bộ không gian đầu vào. Bốn đơn dưới 150.000 đồng đạt cả, nhưng lỗi nằm ở nhánh đơn lớn mà ta chưa thử.
- "Bug, lỗi và sự cố là một thứ." Ngoài đời nói thế được, nhưng khi báo cáo thì khác. Tester mô tả sự cố mình thấy, không khẳng định lỗi nằm ở dòng code nào, vì việc đó chưa được chứng minh. Bài về quy trình xử lý bug ở cuối chương sẽ quay lại điều này.
- "Kiểm thử là bấm thử ứng dụng." Sai ở chỗ bỏ qua phần suy nghĩ: chọn dữ liệu thử, so sánh với yêu cầu, đọc tài liệu, ước lượng rủi ro. ISTQB nhấn mạnh kiểm thử phần lớn là hoạt động trí tuệ.
- "Lập trình viên sửa xong thì không cần test lại." Sai ở chỗ bản sửa cũng có thể sai hoặc làm hỏng chỗ khác, nên cần cả kiểm thử xác nhận lẫn hồi quy.
Điều kiện và giới hạn
- Thuật ngữ ở đây theo ISTQB. Mỗi công ty có thể dùng từ khác (ví dụ gọi sự cố là "incident" hoặc "issue"), nên trong nhóm hãy thống nhất cách gọi ngay từ đầu.
- Chuỗi sai sót, lỗi, sự cố không kín: sự cố còn có thể đến từ môi trường (mất mạng, máy yếu, dữ liệu thử sai) chứ không phải lúc nào cũng có lỗi trong code.
- Ví dụ
CHUTU10và các con số 312, 74, 518.000 đồng là minh họa cho bài, không phải số liệu thật của một doanh nghiệp.
Tự kiểm tra (có đáp án)
Câu 1. Với đơn 200.000 đồng hiện giảm 20.000 thay vì 15.000, hãy chỉ ra đâu là sai sót, đâu là lỗi, đâu là sự cố.
Đáp án: sai sót là việc An bỏ sót vế "tối đa 15.000" khi đọc yêu cầu; lỗi là dòng return subtotal * 0.1; thiếu giới hạn; sự cố là màn hình hiện giảm 20.000 và tổng 180.000 thay vì 185.000.
Câu 2. Chú Tư hỏi: "Tất cả test case đã đạt, vậy chắc chắn không còn lỗi nữa đúng không?". Bạn trả lời thế nào trong một hai câu? Đáp án: "Chưa chắc ạ. Đạt nghĩa là với những dữ liệu đã thử chưa thấy sự cố; em báo cáo cụ thể đã thử gì và chưa thử gì để chú quyết định." Câu trả lời đúng không hứa hết lỗi và nêu rõ phạm vi đã kiểm tra.
Câu 3. An nói đã gỡ lỗi xong nên Bình khỏi cần test lại. Bình nên chạy lại những loại test nào, và vì sao? Đáp án: kiểm thử xác nhận (chạy lại đúng đơn 200.000) để biết lỗi đã hết, và kiểm thử hồi quy (chạy lại các đơn 50.000, 100.000, 150.000 và các chức năng gần đó) để biết bản sửa không làm hỏng chỗ khác.
Điều cần nhớ
- Kiểm thử có ba việc chính: tìm lỗi, cung cấp thông tin để nhóm quyết định, giảm rủi ro.
- Sai sót (error) ở người, lỗi (defect) ở sản phẩm, sự cố (failure) lúc chạy; tester thường thấy sự cố trước.
- Kiểm thử tìm sự cố, gỡ lỗi tìm nguyên nhân và sửa; sau khi sửa phải kiểm thử xác nhận và hồi quy.
- Test đạt chỉ nói rằng chưa thấy lỗi trong phạm vi đã thử, không chứng minh hết lỗi.
- Bài tiếp theo gom bảy nguyên tắc kiểm thử thành ba nhóm dễ nhớ để bạn biết nên thử gì, thử bao nhiêu, thử khi nào.
Nguồn tham khảo
- ISTQB Certified Tester Foundation Level Syllabus v4.0.1, các mục 1.1 (kiểm thử là gì, mục tiêu), 1.1.2 (kiểm thử và gỡ lỗi), 1.2.3 (sai sót, lỗi, sự cố): https://istqb.org/wp-content/uploads/2024/11/ISTQB_CTFL_Syllabus_v4.0.1.pdf
- Bộ thuật ngữ ISTQB (tra cứu error, defect, failure, debugging): https://glossary.istqb.org/