Bảng quyết định và giá trị biên: thiết kế test cho mã giảm giá có nhiều điều kiện

6 giờ tới · 11 phút đọc
Vấn đề: nhiều điều kiện, nhiều cách kết hợp
Mã giảm giá tưởng đơn giản - nhập mã, được giảm. Thực tế thì không phải vậy.
Trong hầu hết hệ thống thương mại điện tử, một mã khuyến mãi phụ thuộc đồng thời vào nhiều điều kiện: hạng thành viên của người dùng, giá trị đơn hàng có đạt ngưỡng tối thiểu không, và mã còn hiệu lực hay đã hết hạn. Ba điều kiện độc lập tạo ra tối đa 2³ = 8 tổ hợp - và đó chỉ là trường hợp mỗi điều kiện chỉ có hai trạng thái (đúng/sai).
Vấn đề không phải là thiếu test case. Vấn đề là chọn tổ hợp nào để test mà không bỏ sót ranh giới quan trọng, đồng thời không lãng phí thời gian vào những tổ hợp cho kết quả giống nhau.
Ba điều kiện độc lập - số tổ hợp tăng theo lũy thừa
Bài này dùng một quy tắc mã giảm giá cụ thể (giả định/minh họa) để đi qua toàn bộ quy trình: phân tích điều kiện, xây dựng bảng quyết định, xác định giá trị biên, và thiết kế danh sách test case cuối cùng.
Hai kỹ thuật chính được dùng:
- Decision Table Testing (kiểm thử bảng quyết định): liệt kê tất cả tổ hợp điều kiện có thể và kết quả tương ứng, sau đó gộp các tổ hợp cho cùng output.
- Boundary Value Analysis (BVA - phân tích giá trị biên): tập trung test ở các giá trị sát ngưỡng (vd: 499.999đ, 500.000đ, 500.001đ) thay vì chỉ test giữa khoảng.
Quy tắc khuyến mãi mẫu (giả định minh họa)
Để có một bài cụ thể, ta dùng quy tắc sau - đây là giả định minh họa, không phải hệ thống thực:
Mã giảm giá SALE20 áp dụng 20% khi thỏa đồng thời:
- Người dùng có hạng thành viên Silver hoặc Gold
- Giá trị đơn hàng ≥ 500.000đ
- Mã chưa hết hạn (hệ thống dùng giờ server, chưa rõ múi giờ)
Nếu không đủ điều kiện: hiển thị thông báo lỗi phù hợp, không áp dụng giảm giá.
Quy tắc gốc - nền tảng để xây bảng quyết định
Trước khi viết bất kỳ test case nào, tester cần làm rõ những điểm mờ trong yêu cầu này:
| Điểm chưa rõ | Câu hỏi cần hỏi BA/PO | Ảnh hưởng đến test |
|---|---|---|
| "Silver hoặc Gold" | Hạng Bronze thì sao? Có hạng nào khác không? | Xác định số phân vùng điều kiện 1 |
| Giá trị đơn ≥ 500.000đ | Tính trước hay sau phí ship? Sau khi áp mã khác chưa? | Xác định input cho BVA |
| "Chưa hết hạn" | Múi giờ nào? Hết hạn lúc 00:00 hay 23:59? | Quyết định test case cho điều kiện 3 |
| Thông báo lỗi | Mỗi điều kiện sai có thông báo riêng không? | Xác định expected result cho từng rule |
Ghi những câu hỏi này vào một tài liệu và gửi cho BA trước khi bắt đầu viết test. Nếu chưa có câu trả lời, ghi rõ giả định trong test case để reviewer biết.
Phân tích điều kiện và xây dựng bảng quyết định
Bảng quyết định (decision table) có cấu trúc gồm hai phần:
- Conditions (điều kiện): các đầu vào ảnh hưởng đến kết quả
- Actions (hành động/kết quả): output tương ứng với từng tổ hợp điều kiện
Bước 1: Liệt kê điều kiện và các trạng thái có thể
Với quy tắc giả định ở trên:
| Điều kiện | Trạng thái |
|---|---|
| C1: Hạng thành viên | Silver/Gold (hợp lệ) / Bronze/Guest (không hợp lệ) |
| C2: Giá trị đơn hàng | ≥ 500.000đ / < 500.000đ |
| C3: Ngày hết hạn | Còn hiệu lực / Đã hết hạn |
Mỗi điều kiện có 2 trạng thái → tổng 2³ = 8 tổ hợp.
Bước 2: Lập bảng đủ 8 tổ hợp
| Rule | C1: Hạng | C2: Giá trị đơn | C3: Hiệu lực | Kết quả |
|---|---|---|---|---|
| R1 | Hợp lệ | ≥ 500k | Còn | Áp dụng 20% |
| R2 | Hợp lệ | ≥ 500k | Hết | Lỗi: mã hết hạn |
| R3 | Hợp lệ | < 500k | Còn | Lỗi: chưa đủ giá trị đơn |
| R4 | Hợp lệ | < 500k | Hết | Lỗi: mã hết hạn (hoặc cả hai?) |
| R5 | Không hợp lệ | ≥ 500k | Còn | Lỗi: không đủ hạng |
| R6 | Không hợp lệ | ≥ 500k | Hết | Lỗi: mã hết hạn (hoặc cả hai?) |
| R7 | Không hợp lệ | < 500k | Còn | Lỗi: không đủ hạng |
| R8 | Không hợp lệ | < 500k | Hết | Lỗi: mã hết hạn (hoặc cả hai?) |
Bảng đủ 8 rule - dấu hỏi ở kết quả là nơi cần hỏi thêm
R4, R6, R8 có nhiều điều kiện sai đồng thời - hệ thống sẽ ưu tiên hiển thị lỗi nào? Đây là câu hỏi cho BA, không phải tester tự quyết định.
Bước 3: Gộp các rule có kết quả tương đồng
Nhìn vào bảng, R3 và R7 đều trả về lỗi liên quan đến giá trị đơn hoặc hạng thành viên khi mã còn hiệu lực. Tuy nhiên, thông báo lỗi khác nhau nên không thể gộp.
R2, R4, R6, R8 đều liên quan đến mã hết hạn. Nếu yêu cầu xác nhận "mã hết hạn được kiểm tra đầu tiên và trả về ngay", thì bốn rule này có thể gộp thành một test case duy nhất - nhưng chỉ gộp sau khi đã xác nhận với BA.
Kết quả sau khi làm rõ: thực tế chỉ cần 5-6 test case đại diện thay vì 8.
Xác định giá trị biên (Boundary Value Analysis)
Bảng quyết định đã xử lý câu hỏi "tổ hợp điều kiện nào". Giá trị biên xử lý câu hỏi tiếp theo: "giá trị cụ thể nào để test điều kiện C2 (giá trị đơn hàng)?"
BVA tập trung vào ba điểm quanh ngưỡng 500.000đ:
| Điểm test | Giá trị | Kỳ vọng | Lý do chọn |
|---|---|---|---|
| Dưới ngưỡng 1 đơn vị | 499.999đ | Từ chối | Ranh giới trực tiếp dưới |
| Đúng ngưỡng | 500.000đ | Chấp nhận | Ngưỡng biên |
| Trên ngưỡng 1 đơn vị | 500.001đ | Chấp nhận | Xác nhận ngưỡng đúng chiều |
Tại sao không test 100.000đ hay 1.000.000đ? Vì chúng nằm sâu trong vùng rõ ràng - ít khả năng lộ bug hơn so với vùng sát ngưỡng.
Tập trung vào ba điểm quanh 500.000đ thay vì rải đều toàn dải
Lưu ý thực tế khi áp dụng BVA ở đây:
- Đơn vị tối thiểu là gì? Nếu hệ thống không hỗ trợ lẻ đồng, test 499.999đ có thể không thực hiện được - cần xác nhận với dev về kiểu dữ liệu lưu trữ (integer, decimal).
- Giá trị đơn tính ở đâu trong flow? Trước hay sau khi áp mã là hai trường hợp khác nhau. Đây vẫn là câu hỏi cho BA.
Giá trị biên cho điều kiện C3 (ngày hết hạn):
C3 cũng có ranh giới - điểm chính xác lúc mã hết hạn. Nếu mã hết hạn lúc 23:59:59 ngày 31/12, thì cần test:
- 23:59:58 cùng ngày → còn hiệu lực
- 23:59:59 → ranh giới (cần hỏi: inclusive hay exclusive?)
- 00:00:00 ngày hôm sau → đã hết hạn
Múi giờ server khác múi giờ user là một nguồn bug phổ biến. Ghi đây là điểm cần làm rõ trong tài liệu test.
Danh sách test case cuối cùng
Kết hợp bảng quyết định và giá trị biên, dưới đây là bộ test case đại diện cho quy tắc giả định SALE20. Tất cả dữ liệu đầu vào và kết quả mong đợi đều là giả định minh họa.
| TC# | Hạng | Giá trị đơn | Trạng thái mã | Expected Result | Kỹ thuật |
|---|---|---|---|---|---|
| TC01 | Gold | 500.000đ | Còn hiệu lực | Áp dụng 20%, hiển thị giá sau giảm | Decision Table R1 + BVA |
| TC02 | Silver | 500.001đ | Còn hiệu lực | Áp dụng 20% | BVA (trên ngưỡng) |
| TC03 | Gold | 499.999đ | Còn hiệu lực | Lỗi: giá trị đơn chưa đủ điều kiện | BVA (dưới ngưỡng) |
| TC04 | Gold | 500.000đ | Hết hạn | Lỗi: mã đã hết hạn | Decision Table R2 |
| TC05 | Bronze | 500.000đ | Còn hiệu lực | Lỗi: hạng thành viên không đủ điều kiện | Decision Table R5 |
| TC06 | Guest | 499.999đ | Hết hạn | Lỗi: [cần xác nhận ưu tiên hiển thị lỗi] | Decision Table R8 - còn mờ |
| TC07 | Gold | 500.000đ | Hết hạn (ranh giới) | [cần xác nhận: 23:59:59 inclusive?] | BVA cho C3 |
7 test case bao phủ các ranh giới quan trọng thay vì liệt kê mọi tổ hợp
TC06 và TC07 được giữ lại dù chưa rõ expected result - đây là cách ghi nhận test case đang chờ làm rõ, không phải xóa đi. Ghi chú rõ "pending BA confirmation" trong test management tool.
Những gì bộ test này không bao gồm (và lý do):
- Performance: bao nhiêu mã được áp đồng thời - ngoài scope functional testing
- Security: bypass điều kiện bằng request giả mạo - cần test riêng
- Concurrency: hai user cùng dùng một mã lúc hết hạn - cần test riêng với môi trường phù hợp
Tải template bảng test case này về để điền vào dự án của bạn: Tải template test case (Markdown)
Ghi nhận quyết định khi yêu cầu chưa rõ
Phần này thường bị bỏ qua trong tài liệu test - nhưng lại là thứ cứu bạn khi bug xảy ra lúc regression.
Khi yêu cầu còn mơ hồ, tester có ba lựa chọn:
- Hỏi và chờ - đúng nhưng chậm khi deadline gần
- Tự giả định và ghi lại - nhanh hơn, nhưng phải minh bạch
- Viết test case "chờ xác nhận" - giữ placeholder trong test suite, đánh dấu rõ
Lựa chọn 3 kết hợp với 1 là cách tốt nhất. Viết test case với expected result là "[Pending: cần xác nhận với BA về X]", và gửi câu hỏi song song. Khi có câu trả lời, điền vào - không cần viết lại từ đầu.
Ghi rõ giả định trong test case - quan trọng hơn là bỏ trống hoặc tự quyết định
Template ghi nhận giả định (giả định minh họa):
TC07 - Ranh giới hết hạn
Input: Hạng Gold, đơn 500.000đ, mã hết hạn lúc 23:59:59
Giả định: Hệ thống dùng múi giờ UTC+7; 23:59:59 là inclusive (mã còn hiệu lực)
Expected: Áp dụng 20%
Nguồn giả định: Chưa xác nhận - pending email ngày [ngày gửi]
Trạng thái: BLOCKED - chờ BA xác nhận
Cấu trúc này làm rõ ba thứ: input, giả định, và ai chịu trách nhiệm xác nhận. Khi bug xảy ra, reviewer không mất thời gian đoán bạn đang nghĩ gì lúc viết test.
Một điểm cuối về múi giờ: nếu hệ thống phục vụ người dùng ở nhiều múi giờ khác nhau, đây không còn là câu hỏi nhỏ - đây là một functional requirement cần document riêng. Ghi nhận điểm này trong test plan, không chỉ trong test case.
Tham khảo: ISTQB Foundation Level Syllabus - Decision Table Testing và Boundary Value Analysis. Quy tắc và dữ liệu trong bài là giả định minh họa, không đại diện cho bất kỳ hệ thống thực tế nào.