Kiểm thử phần mềm (Software Testing)
1. Tổng quan
A. Định nghĩa
Hoạt động phát hiện các lỗi (defect) tiềm ẩn trong phần mềm và xác nhận, kiểm chứng việc đáp ứng yêu cầu nhằm bảo đảm chất lượng. Mục đích là phòng ngừa lỗi và nâng cao độ tin cậy.
Một hiểu lầm phổ biến về kiểm thử là cho rằng đó là "công việc chứng minh không có lỗi". Tuy nhiên, phần mềm có tổ hợp đầu vào gần như vô hạn nên không thể xác nhận mọi trường hợp, và vì vậy điều kiểm thử có thể làm chỉ là làm lộ ra sự tồn tại của lỗi. Phải xuất phát từ nhận thức này thì kiểm thử mới thành lập như một hoạt động chiến lược "tìm lỗi hiệu quả nhất với nguồn lực hạn chế". Kiểm thử bao gồm cả kiểm định (Verification, có làm đúng cách không) và xác nhận (Validation, có làm đúng thứ cần làm không), và đã phát triển theo hướng vượt ra ngoài việc kiểm tra chất lượng sau sự việc để phòng ngừa lỗi ngay từ đầu.
B. Sự cần thiết
Lỗi càng được phát hiện muộn thì chi phí sửa càng tăng theo cấp số nhân. Theo quy tắc kinh nghiệm lâu đời, lỗi ở giai đoạn yêu cầu và thiết kế nếu được phát hiện ở giai đoạn vận hành có thể tốn chi phí gấp hàng chục lần. Do đó, kiểm thử không phải là kiểm tra đơn thuần mà là phương tiện bảo đảm chất lượng lọc lỗi sớm và với chi phí thấp, và các nguyên lý dưới đây là chỉ dẫn thực hành để đạt được mục tiêu này.
2. Các nguyên lý kiểm thử phần mềm (A)
7 nguyên lý kiểm thử là một logic thống nhất liên kết với nhau. Vì "kiểm thử hoàn hảo là không thể" nên phải lựa chọn theo rủi ro (phụ thuộc ngữ cảnh), vì lỗi "tập trung ở số ít mô-đun" nên dồn nguồn lực vào đó, và vì các ca kiểm thử tạo ra như vậy nếu lặp lại sẽ mất hiệu lực (nghịch lý thuốc trừ sâu) nên phải liên tục cập nhật. Bảng dưới đây là từng nguyên lý và hàm ý thực hành của nó.
| Nguyên lý | Nội dung và hàm ý |
|---|---|
| Chứng minh sự tồn tại của lỗi | Làm rõ sự tồn tại của lỗi nhưng không chứng minh được sự không tồn tại → mục đích kiểm thử là phát hiện lỗi |
| Kiểm thử hoàn hảo là không thể | Không thể kiểm thử mọi tổ hợp đầu vào, đường đi → lựa chọn dựa trên rủi ro |
| Tập trung sớm (Early Testing) | Kiểm thử từ đầu quá trình phát triển → giảm chi phí sửa lỗi |
| Tập trung lỗi (Pareto) | Lỗi tập trung ở số ít mô-đun → ưu tiên phân bổ nguồn lực |
| Nghịch lý thuốc trừ sâu | Lặp lại cùng một kiểm thử thì không tìm được lỗi mới → cập nhật ca kiểm thử |
| Phụ thuộc ngữ cảnh | Kiểm thử khác nhau tùy theo miền nghiệp vụ và rủi ro |
| Ngụy biện về sự vắng mặt của lỗi | Dù không có lỗi, nếu không đáp ứng yêu cầu thì chất lượng vẫn kém |
Đặc biệt, "ngụy biện về sự vắng mặt của lỗi" chỉ ra rằng dù về mặt kỹ thuật không có bug, nếu không làm ra thứ người dùng muốn thì cũng vô ích, nhắc nhở rằng kiểm thử phải vượt ra ngoài kiểm chứng mã để bao gồm cả xác nhận tính hợp lý của yêu cầu.
3. Kiểm thử hộp đen vs hộp trắng (B)
Hai cách tiếp cận khác nhau ở "tạo ca kiểm thử dựa trên căn cứ nào". Hộp đen không biết cấu trúc bên trong, chỉ nhìn đặc tả để kiểm chứng sự phù hợp giữa đầu vào–đầu ra, nên bắt tốt các lỗi ở góc nhìn người dùng và yêu cầu, nhưng khó biết mã không được thực thi (dead code) hay đường đi bên trong bị bỏ sót. Hộp trắng nhìn cấu trúc bên trong của mã để kiểm chứng mọi nhánh và đường đi có được thực thi hay không, nên mạnh về lỗi logic, nhưng lại không phát hiện được chức năng bị bỏ sót không có trong đặc tả, vì nó không có trong mã. Do tính bổ trợ lẫn nhau này, phải dùng song song cả hai.
| Phân loại | Hộp đen | Hộp trắng |
|---|---|---|
| Góc nhìn | Dựa trên đặc tả (không biết cấu trúc bên trong) | Dựa trên cấu trúc, logic bên trong |
| Mục đích | Xác nhận đáp ứng chức năng, yêu cầu | Kiểm chứng độ bao phủ mã, đường đi |
| Kỹ thuật | Phân vùng tương đương, giá trị biên, bảng quyết định, chuyển trạng thái | Bao phủ câu lệnh, quyết định, điều kiện |
| Chủ thể thực hiện | Chủ yếu góc nhìn QA, người dùng | Góc nhìn nhà phát triển |
| Giới hạn | Bỏ sót đường đi bên trong, dead code | Không phát hiện chức năng bị bỏ sót trong đặc tả |
Ví dụ, với đặc tả "cho phép nhập 1~100", phân tích giá trị biên của hộp đen tập trung kiểm chứng 0·1·100·101 để nhắm vào lỗi off-by-one. Đây là việc tận dụng quy tắc kinh nghiệm rằng lỗi thường xảy ra ở biên.
4. Kỹ thuật kiểm thử (C)
Các kỹ thuật dẫn xuất ca kiểm thử chia thành ba nhánh theo căn cứ. Dựa trên đặc tả dẫn xuất ca kiểm thử từ việc phải làm gì, dựa trên cấu trúc từ việc mã được viết như thế nào, và dựa trên kinh nghiệm từ trực giác của người kiểm thử. Ba nhánh lấp đầy điểm mù của nhau.
flowchart TB
T[Kỹ thuật kiểm thử] --> S[Dựa trên đặc tả]
T --> C[Dựa trên cấu trúc]
T --> E[Dựa trên kinh nghiệm]
S --> S1[Phân vùng tương đương·giá trị biên<br/>bảng quyết định·chuyển trạng thái·use case]
C --> C1[Bao phủ câu lệnh·quyết định·điều kiện<br/>MC-DC]
E --> E1[Đoán lỗi·kiểm thử khám phá<br/>checklist]
style T fill:#e8f0fe,stroke:#2f6fed,stroke-width:2px
Dựa trên đặc tả (hộp đen) dẫn xuất ca kiểm thử từ yêu cầu và đặc tả; tiêu biểu là phân vùng tương đương gom đầu vào thành các nhóm giá trị đại diện, giá trị biên tập trung vào biên, và bảng quyết định sắp xếp tổ hợp điều kiện thành bảng. Dựa trên cấu trúc (hộp trắng) đo mức độ thực thi cấu trúc mã bằng độ bao phủ; so với bao phủ câu lệnh thực thi mọi câu lệnh, bao phủ quyết định/điều kiện xem xét cả nhánh và điều kiện nghiêm ngặt hơn, và xa hơn nữa là MC-DC được yêu cầu cho các hệ thống an toàn trọng yếu. Dựa trên kinh nghiệm gồm đoán lỗi (error guessing) — người kiểm thử phỏng đoán nơi có khả năng có lỗi — và kiểm thử khám phá (exploratory testing) — vừa học vừa khám phá mà không có kế hoạch trước.
| Kỹ thuật | Mô tả |
|---|---|
| Dựa trên đặc tả (hộp đen) | Dẫn xuất từ yêu cầu, đặc tả (phân vùng tương đương, giá trị biên, bảng quyết định, chuyển trạng thái) |
| Dựa trên cấu trúc (hộp trắng) | Độ bao phủ cấu trúc mã (câu lệnh, quyết định, điều kiện, MC-DC) |
| Dựa trên kinh nghiệm | Kinh nghiệm, trực giác của người kiểm thử (đoán lỗi, kiểm thử khám phá) |
5. Các điểm cần cân nhắc và hàm ý
Từ góc nhìn Kỹ sư chuyên nghiệp, cốt lõi của kiểm thử hiệu quả là kết hợp các kỹ thuật và ưu tiên dựa trên rủi ro. Phải dùng cùng lúc các kỹ thuật dựa trên đặc tả, cấu trúc và kinh nghiệm thì các điểm mù mới được lấp đầy và độ bao phủ được tối đa hóa, và nguồn lực được ưu tiên phân bổ cho các vùng tập trung lỗi (Pareto) và có rủi ro cao. Cũng phải phản ánh sự thay đổi của phương thức phát triển. Trong môi trường CI/CD, tự động hóa kiểm thử là bắt buộc để bắt nhanh lỗi hồi quy, và TDD — viết kiểm thử trước để dẫn dắt thiết kế — cùng pipeline tự động kiểm chứng mỗi lần thay đổi mã đã trở thành tiêu chuẩn. Gần đây, kiểm thử mở rộng sang sinh ca kiểm thử dựa trên AI, kiểm thử hồi quy hình ảnh, v.v., nhưng nền tảng vẫn nằm ở nguyên lý lọc lỗi sớm "ngay từ đầu, lấy rủi ro làm trọng tâm, kết hợp nhiều kỹ thuật".
Tóm tắt một câu: Kiểm thử phần mềm là hoạt động phát hiện và phòng ngừa lỗi từ sớm, dựa trên 7 nguyên lý với tiền đề chỉ có thể chứng minh sự tồn tại của lỗi, kết hợp các kỹ thuật dựa trên đặc tả, cấu trúc và kinh nghiệm theo trọng tâm rủi ro với góc nhìn bổ trợ lẫn nhau của hộp đen (đặc tả) và hộp trắng (cấu trúc).