Phân tích giá trị biên: thử đúng chỗ ranh giới nơi lỗi hay nằm
Xem thửCà Phê Chú Tư có chính sách: đơn từ 100.000 đồng trở lên được miễn phí giao hàng, đơn nhỏ hơn thì phí giao là 15.000 đồng. Bình thử ba đơn: 50.000 đồng (tính phí 15.000, đúng), 150.000 đồng (miễn phí, đúng) và 250.000 đồng (miễn phí, đúng). Cả ba đều đạt, Bình ghi "chức năng phí giao đạt".
Tuần sau, ba khách đặt đúng 100.000 đồng và đều bị tính 15.000 đồng phí giao. Họ nhắn: "Quảng cáo ghi từ 100.000 mà". Lập trình viên mở code ra thì thấy dòng kiểm tra viết total > 100000 thay vì total >= 100000: một dấu bằng bị quên.
Ba đơn của Bình không hề sai về phương pháp: chúng đúng theo cách chia nhóm của bài trước, mỗi nhóm một đại diện. Điều gì khiến chúng vẫn để lọt lỗi? Trước khi đọc tiếp, hãy tự trả lời bằng cách viết ra giấy: nếu ngưỡng là 100.000 đồng, bạn sẽ chọn những tổng tiền nào để chắc chắn bắt được lỗi một dấu so sánh?
Sau bài này, bạn có thể
- Tìm các biên của một khoảng giá trị và dịch đúng các cụm từ như "từ", "trên", "tối đa" thành biên thật.
- Chọn hai giá trị cho mỗi biên (biên và giá trị lân cận bên kia), nhắc được cách ba giá trị, và viết bảng test có kết quả mong đợi.
- Kết hợp với phân vùng tương đương để có bộ test đầy đủ cho một form, đếm đúng số test.
Cần biết trước: phân vùng tương đương: chia dữ liệu thành lớp hợp lệ và không hợp lệ, mỗi lớp một đại diện (bài trước).
Mô hình tư duy 1: lỗi sống ở đường ranh giới
Phân vùng tương đương chọn một giá trị đại diện cho mỗi lớp, thường là giá trị "ở giữa". Giá trị ở giữa hầu như luôn đúng, vì dù lập trình viên viết < hay <= thì kết quả cho giá trị ở giữa vẫn như nhau. Chỉ ở sát ranh giới giữa hai lớp, hai cách viết mới cho hai kết quả khác nhau.
Đó là lý do phân tích giá trị biên (boundary value analysis) ra đời: lỗi lệch một (off-by-one) xảy ra rất thường xuyên, và nó chỉ lộ ra ở biên. Hãy xem trên ô Số ly (nhận số nguyên từ 1 đến 10). Điều kiện đúng của code là qty >= 1 && qty <= 10. Bốn lỗi lệch một có thể xảy ra, mỗi lỗi sai ở một dấu:
| Phiên bản code | Lỗi gây ra |
|---|---|
qty > 1 && qty <= 10 | không nhận 1 ly (thừa dấu bằng ở biên dưới) |
qty >= 1 && qty < 10 | không nhận 10 ly (thiếu dấu bằng ở biên trên) |
qty >= 0 && qty <= 10 | nhận cả 0 ly (biên dưới bị lệch xuống) |
qty >= 1 && qty <= 11 | nhận cả 11 ly (biên trên bị lệch lên) |
Ta chạy bảy giá trị qua bốn phiên bản lỗi và ghi lại giá trị nào làm hai phiên bản khác nhau (X là phát hiện lỗi). Kết quả từ chương trình kiểm tra, không phải đoán:
| Giá trị thử | Không nhận 1 | Không nhận 10 | Nhận cả 0 | Nhận cả 11 |
|---|---|---|---|---|
| 0 | X | |||
| 1 | X | |||
| 2 | ||||
| 5 | ||||
| 9 | ||||
| 10 | X | |||
| 11 | X |
Mỗi lỗi chỉ bị bắt bởi đúng một giá trị sát biên. Các giá trị 2, 5, 9 (nằm giữa) không bắt được lỗi nào trong bốn lỗi. Bộ test "3, 5, 8" vì vậy cho cảm giác an toàn giả. Bộ bốn giá trị 0, 1, 10, 11 bắt được cả bốn.
Mô hình tư duy 2: hai giá trị cho mỗi biên
Với mỗi biên (đường ranh giữa lớp này và lớp bên cạnh), ta lấy giá trị biên (giá trị đầu tiên hoặc cuối cùng của lớp) và giá trị lân cận gần nhất của lớp bên cạnh. Theo cách đặt tên của ISTQB, đó là phân tích giá trị biên 2 giá trị. Khóa học này dùng 2 giá trị làm mặc định.
Ô Số ly có hai biên: 0 và 1 (ranh giữa "nhỏ hơn 1" và "hợp lệ"), 10 và 11 (ranh giữa "hợp lệ" và "lớn hơn 10"). Vậy bộ 2 giá trị là 0, 1, 10, 11, tổng 4 test.
Còn 3 giá trị: mỗi biên lấy giá trị biên cùng cả hai lân cận hai bên. Ô Số ly thành 0, 1, 2, 9, 10, 11, tổng 6 test. Giá trị thêm (2 và 9) giúp khi bạn nghi ngờ code xử lý riêng quanh biên, ví dụ khi lỗi cũ thường nằm sát biên hoặc khi chức năng quan trọng. Ở các ví dụ còn lại của bài ta dùng 2 giá trị.
Giá trị lân cận là bao nhiêu? Phụ thuộc vào bước nhỏ nhất của dữ liệu. Số ly là số nguyên nên lân cận cách 1. Giá món của quán luôn là bội số của 1.000 đồng, nên tổng tiền hàng nhỏ hơn 100.000 mà gần nhất là 99.000 (không phải 99.999). Nếu hệ thống cho phép đồng lẻ, lân cận mới là 99.999. Điều này phải được xác định từ đặc tả, không phải đoán.
Dịch lời văn thành biên
Tiếng Việt có nhiều cách nói về ngưỡng, và mỗi cách hiểu khác nhau về việc có gồm giá trị ngưỡng hay không:
| Cụm trong đặc tả | Có gồm mốc không | Ví dụ với mốc 100.000 |
|---|---|---|
| từ 100.000 trở lên, ít nhất 100.000 | gồm | 100.000 thuộc lớp này |
| trên 100.000, quá 100.000 | không gồm | 100.000 thuộc lớp bên dưới |
| từ 100.000 trở xuống, tối đa 100.000 | gồm | 100.000 thuộc lớp này |
| dưới 100.000 | không gồm | 100.000 thuộc lớp bên trên |
| từ 16 đến 22 | gồm cả hai đầu | 16 và 22 đều thuộc lớp |
Khi câu chữ không rõ (ví dụ "đơn trên 100.000 miễn phí" hay "100.000 trở lên"), đừng tự chọn. Đó là một lỗi đặc tả, hãy hỏi người viết đặc tả. Đây cũng là một cách kiểm thử tĩnh.
Ví dụ 1: ô Số ly
Bốn giá trị 0, 1, 10, 11 với kết quả mong đợi (cà phê sữa 25.000 đồng mỗi ly):
| Test | Số ly | Kết quả mong đợi | Biên phủ |
|---|---|---|---|
| B1 | 0 | báo lỗi, giỏ giữ nguyên | giá trị ngay dưới biên dưới |
| B2 | 1 | thêm 1 ly, tiền hàng 25.000 | biên dưới |
| B3 | 10 | thêm 10 ly, tiền hàng 250.000 | biên trên |
| B4 | 11 | báo lỗi, giỏ giữ nguyên | giá trị ngay trên biên trên |
Đang tải sơ đồ…
Cách đọc hình: đi từ trên xuống. Ô cam là câu hỏi quan trọng nhất: giá trị có thứ tự (số, ngày, tiền) hay không. Nếu không, chỉ cần phân vùng tương đương (ô cyan). Nếu có, ta đánh dấu các biên, lấy biên và lân cận của nó, kiểm tra bước nhỏ nhất của dữ liệu để biết lân cận là bao nhiêu, rồi mới viết kết quả mong đợi ở ô xanh lá.
Animation tiếp theo chạy một lỗi lệch một thật trên ô Số ly: code kiểm tra qty < 10 thay vì qty <= 10. Bấm nút biến thể để đổi bộ test sang các giá trị "giữa lớp" và xem lỗi có lọt không.
Đang tải Animation…
Ví dụ 2: tuổi nhận ưu đãi Tuổi Trẻ
Ô Tuổi nhận số nguyên từ 1 đến 120, và ưu đãi giảm 10% cho khách từ 16 đến 22 tuổi. Có bốn biên: 0 và 1 (biên dưới của ô), 15 và 16 (vào ưu đãi), 22 và 23 (ra khỏi ưu đãi), 120 và 121 (biên trên của ô). Mỗi biên hai giá trị, tổng 4 x 2 = 8 giá trị. Giả sử khách mua 5 ly cà phê sữa (125.000 đồng):
| Test | Tuổi | Kết quả mong đợi | Biên phủ |
|---|---|---|---|
| A1 | 0 | báo lỗi tuổi | dưới biên dưới của ô |
| A2 | 1 | hợp lệ, không ưu đãi, 125.000 | biên dưới của ô |
| A3 | 15 | hợp lệ, không ưu đãi, 125.000 | ngay dưới ngưỡng ưu đãi |
| A4 | 16 | giảm 10%, còn 112.500 | biên dưới của ưu đãi |
| A5 | 22 | giảm 10%, còn 112.500 | biên trên của ưu đãi |
| A6 | 23 | hợp lệ, không ưu đãi, 125.000 | ngay trên ngưỡng ưu đãi |
| A7 | 120 | hợp lệ, không ưu đãi, 125.000 | biên trên của ô |
| A8 | 121 | báo lỗi tuổi | trên biên trên của ô |
Cũng như ô Số ly, mỗi lỗi lệch một ở ngưỡng ưu đãi chỉ bị bắt bởi một giá trị: viết age > 16 thay vì age >= 16 thì chỉ A4 phát hiện; viết age >= 15 thì chỉ A3 phát hiện; viết age < 22 thì chỉ A5; viết age <= 23 thì chỉ A6.
Ví dụ 3: ngưỡng miễn phí giao hàng
Quy định: tiền hàng từ 100.000 đồng trở lên thì miễn phí giao; dưới đó thì phí giao là 15.000 đồng. Biên là 100.000 (lớp "miễn phí") và 99.000 (lớp "tính phí"), bước 1.000 đồng. Hai test:
| Test | Giỏ hàng | Tiền hàng | Kết quả mong đợi |
|---|---|---|---|
| F1 | 2 trà đào (35.000) và 1 bạc xỉu (29.000) | 99.000 | phí giao 15.000, phải trả 114.000 |
| F2 | 4 cà phê sữa (25.000) | 100.000 | miễn phí giao, phải trả 100.000 |
Với code lỗi total > 100000, F1 vẫn cho phí 15.000 (đúng), F2 cho phí 15.000 (sai). Chỉ F2 phát hiện lỗi. Ba đơn 50.000, 150.000, 250.000 của Bình đều nằm giữa lớp nên không thấy gì. Nếu bạn thêm test 101.000 (bộ 3 giá trị) thì nó cũng đạt vì 101.000 là lớn hơn 100.000 theo cả hai cách viết. Animation thứ hai cho bạn thử đổi biên.
Đang tải Animation…
Kết hợp với phân vùng tương đương: bộ test cho form hai ô
Phân vùng tương đương lo các lớp không có thứ tự (chữ, số thập phân, ô trống), phân tích giá trị biên lo ranh giới của các lớp có thứ tự. Với form đặt hàng có ô Số ly và ô Tuổi:
- Ô Số ly: biên 0, 1, 10, 11 (4 giá trị); thêm các lớp không có thứ tự: 2,5, abc, để trống (3 giá trị).
- Ô Tuổi: biên 0, 1, 15, 16, 22, 23, 120, 121 (8 giá trị); thêm lớp không phải số: abc (1 giá trị).
Quy tắc ghép vẫn như bài trước: giá trị hợp lệ ghép chung được, giá trị không hợp lệ phải đi riêng. Giá trị hợp lệ: số ly 1 và 10 (2 giá trị); tuổi 1, 15, 16, 22, 23, 120 (6 giá trị). Giá trị không hợp lệ: số ly 5 giá trị (0, 11, 2,5, abc, trống), tuổi 3 giá trị (0, 121, abc). Số test = 6 (lớn nhất của hai ô hợp lệ) + 5 + 3 = 14 test:
| Test | Số ly | Tuổi | Kết quả mong đợi | Giá trị phủ |
|---|---|---|---|---|
| C01 | 1 | 1 | 25.000, không ưu đãi | ly 1, tuổi 1 |
| C02 | 10 | 15 | 250.000, không ưu đãi | ly 10, tuổi 15 |
| C03 | 1 | 16 | giảm 10%: 22.500 | tuổi 16 |
| C04 | 10 | 22 | giảm 10%: 225.000 | tuổi 22 |
| C05 | 1 | 23 | 25.000, không ưu đãi | tuổi 23 |
| C06 | 10 | 120 | 250.000, không ưu đãi | tuổi 120 |
| C07 | 0 | 19 | báo lỗi số ly | ly 0 |
| C08 | 11 | 19 | báo lỗi số ly | ly 11 |
| C09 | 2,5 | 19 | báo lỗi số ly | ly thập phân |
| C10 | abc | 19 | báo lỗi số ly | ly là chữ |
| C11 | (trống) | 19 | báo lỗi số ly | ly để trống |
| C12 | 5 | 0 | báo lỗi tuổi | tuổi 0 |
| C13 | 5 | 121 | báo lỗi tuổi | tuổi 121 |
| C14 | 5 | abc | báo lỗi tuổi | tuổi là chữ |
Kiểm lại phép đếm: ô Số ly cần 7 giá trị (4 biên + 3 ngoài thứ tự), ô Tuổi cần 9 giá trị (8 biên + 1), tổng 16 giá trị. Chúng nằm trong 14 test vì 8 giá trị hợp lệ (2 của số ly và 6 của tuổi) được ghép vào 6 test C01 đến C06, mỗi test mang một giá trị của mỗi ô. So với 11 test của bài trước, bộ này thêm 3 test (14 - 11), đổi lại bắt được các lỗi lệch một ở những biên mà bộ 11 test bỏ qua (các giá trị đại diện 5, 10, 19, 40 không bao giờ sát biên).
Bản đồ biên của ứng dụng Chú Tư
| Chức năng | Biên | Hai giá trị cần thử |
|---|---|---|
| Số ly | 1 đến 10 | 0 ; 1 ; 10 ; 11 |
| Tuổi ưu đãi | 16 đến 22 | 15 ; 16 ; 22 ; 23 |
| Miễn phí giao | từ 100.000 | 99.000 ; 100.000 |
| Đơn tối thiểu của mã CHUTU10 | từ 50.000 | 49.000 ; 50.000 |
| Trần giảm của mã CHUTU10 | tiền hàng 200.000 (10% đúng bằng 20.000) | 200.000 ; 201.000 |
| Hạn dùng mã CHUTU10 | đến hết 31/12/2026 | 31/12/2026 ; 01/01/2027 |
Biên không chỉ là số: ngày tháng, giờ và độ dài chuỗi cũng có biên. Hạn dùng của mã là một biên ngày, giá trị lân cận cách đúng một ngày.
Hiểu lầm thường gặp
- "Biên chỉ là số lớn nhất và nhỏ nhất của ô." Sai ở chỗ mọi ranh giới giữa hai lớp hành vi đều là biên, kể cả ngưỡng ưu đãi 16 và 22 nằm giữa ô Tuổi. Ô Tuổi có bốn biên, không phải hai.
- "Chỉ thử đúng giá trị biên là đủ, không cần giá trị bên kia." Sai ở chỗ giá trị lân cận bên kia (0, 11, 99.000) kiểm tra rằng lớp bên cạnh thật sự khác. Thiếu nó, lỗi nhận thừa giá trị (như
qty >= 0) sẽ lọt. - "Phân tích giá trị biên thay được phân vùng tương đương." Sai ở chỗ biên chỉ có nghĩa với lớp có thứ tự. Ô để trống hay chữ abc không có biên, vẫn cần phân vùng.
- "Giá trị lân cận luôn cách 1." Sai ở chỗ nó cách đúng một bước nhỏ nhất của dữ liệu: 1 với số ly, 1.000 đồng với tiền hàng, một ngày với hạn dùng.
Điều kiện và giới hạn
Kỹ thuật này chỉ hiệu quả khi đặc tả nêu ngưỡng rõ ràng. Nó giả định mỗi lớp có thứ tự, và cho kết quả tốt với lỗi lệch một nhưng không bắt được lỗi ở giá trị riêng lẻ giữa lớp. Với ngưỡng tính từ nhiều giá trị (tổng tiền hàng từ nhiều món), bạn phải dựng giỏ hàng đúng tổng như F1 và F2 mới thử được biên.
Tự kiểm tra (có đáp án)
Câu 1. Ô Số topping nhận số nguyên từ 0 đến 3. Liệt kê bộ giá trị theo hai giá trị mỗi biên.
Đáp án: hai biên, bốn giá trị: -1 và 0 (biên dưới), 3 và 4 (biên trên). Với ba giá trị thì thành -1, 0, 1, 2, 3, 4, tức 6 giá trị. Kiểm lại: 2 biên x 2 giá trị = 4.
Câu 2. Đặc tả: "mã GIAM5 chỉ dùng cho đơn dưới 500.000 đồng". Bước tiền hàng là 1.000 đồng. Hai giá trị cần thử ở biên là gì và kết quả mong đợi?
Đáp án: biên trên của lớp hợp lệ là 499.000 (dùng được mã) và giá trị lân cận bên kia là 500.000 (không dùng được vì "dưới" không gồm mốc). Nếu đặc tả viết "tối đa 500.000" thì 500.000 mới dùng được, nên phải hỏi lại để xác định.
Câu 3. Code kiểm tra ưu đãi viết age > 16. Trong tám giá trị A1 đến A8, những test nào thất bại và vì sao?
Đáp án: chỉ A4 (tuổi 16) thất bại, vì code coi 16 là chưa đủ tuổi nên không giảm 10%, trong khi mong đợi là giảm. Các giá trị khác (0, 1, 15, 22, 23, 120, 121) cho cùng kết quả ở hai cách viết, nên không phát hiện lỗi.
Điều cần nhớ
- Lỗi lệch một chỉ lộ ra ở sát biên; giá trị giữa lớp gần như không bao giờ bắt được nó.
- Mỗi biên thử hai giá trị: biên và giá trị lân cận của lớp bên cạnh, cách nhau một bước nhỏ nhất của dữ liệu.
- Dịch đúng "từ, trên, dưới, tối đa" thành biên; câu chữ mơ hồ thì hỏi lại, đừng tự đoán.
- Phân vùng tương đương lo lớp, giá trị biên lo ranh giới; bộ test cho form 2 ô của quán là 14 test.
- Bài sau xử lý tình huống nhiều điều kiện cùng quyết định một kết quả: bảng quyết định.
Nguồn tham khảo
- ISTQB Glossary, mục boundary value analysis: https://glossary.istqb.org/
- ISTQB Certified Tester Foundation Level (CTFL) v4.0, phần phân tích giá trị biên 2 giá trị và 3 giá trị: https://istqb.org/certifications/certified-tester-foundation-level-ctfl-v4-0/