Menu
ESC

Nhập từ khóa để tìm kiếm

↑↓ Di chuyển
Enter Mở
ESC Đóng

Đang tải...

Boundary Value Analysis (BVA)

Software Testing Fundamentals Bài 9/60

Mở đầu — vì sao bài này quan trọng

Nếu bạn đã học qua bài Equivalence Partitioning (EP), bạn sẽ nhớ ý tưởng cốt lõi: thay vì test hàng nghìn giá trị đầu vào, ta chia chúng thành các "lớp tương đương" và chỉ cần test một đại diện cho mỗi lớp. EP giúp giảm số lượng test case một cách thông minh. Nhưng EP có một điểm mù chết người: nó giả định rằng mọi giá trị trong một lớp đều được hệ thống xử lý y hệt nhau. Trong thực tế, điều đó gần đúng — nhưng "gần đúng" là chưa đủ với một tester giỏi.

Boundary Value Analysis (BVA) — Phân tích giá trị biên — chính là người anh em song sinh của EP, ra đời để bịt đúng cái điểm mù đó. Triết lý của BVA gói gọn trong một câu mà bạn nên khắc vào đầu: bug thích trốn ở biên. Ở giữa một lớp tương đương, code hầu như luôn chạy đúng. Nhưng ngay tại ranh giới — chỗ chuyển từ "hợp lệ" sang "không hợp lệ", chỗ lập trình viên phải viết < hay <=, > hay >= — là nơi các lỗi off-by-one (lệch một đơn vị) sinh sôi nảy nở.

Vì sao lại thế? Vì con người viết code, và con người rất hay nhầm giữa "nhỏ hơn" và "nhỏ hơn hoặc bằng". Một dev mệt mỏi lúc 11 giờ đêm gõ if (age < 18) trong khi yêu cầu là "từ đủ 18 tuổi mới được đăng ký" — thế là một người đúng 18 tuổi bị hệ thống từ chối. Lỗi này không bao giờ lộ ra nếu bạn test với tuổi 25 hay tuổi 10. Nó chỉ lộ ra khi bạn test đúng con số 18. BVA dạy bạn cách săn chính xác những con số đó. Đây là một trong những kỹ thuật cho tỷ lệ "tìm bug trên mỗi test case" cao nhất trong toàn bộ kho vũ khí của tester — lý do vì sao nó luôn xuất hiện trong đề thi ISTQB và trong mọi buổi phỏng vấn QA.

Khái niệm cốt lõi

Biên là gì?

Với mỗi lớp tương đương có thứ tự (ordered), luôn tồn tại hai đầu mút: giá trị nhỏ nhất và giá trị lớn nhất được chấp nhận. Đó là biên (boundary). Ví dụ, một ô nhập "số lượng sản phẩm" cho phép từ 1 đến 100. Lớp hợp lệ là [1, 100]. Hai biên của nó là 1100.

BVA tập trung test tại các biên này và ngay sát chúng, vì đó là nơi hành vi của phần mềm thay đổi trạng thái — từ chấp nhận sang từ chối.

Quy tắc 2-value (Two-Value BVA)

Đây là biến thể phổ biến và cổ điển nhất. Với mỗi biên, bạn test đúng 2 giá trị: giá trị ngay tại biên và giá trị ngay bên kia biên (lệch 1 đơn vị nhỏ nhất).

Với miền hợp lệ [1, 100]:

  • Biên dưới: test 1 (biên hợp lệ) và 0 (ngay dưới biên, không hợp lệ)
  • Biên trên: test 100 (biên hợp lệ) và 101 (ngay trên biên, không hợp lệ)
Tổng cộng 4 giá trị: 0, 1, 100, 101. Logic ở đây là: nếu dev viết nhầm < thành <= hoặc ngược lại, một trong bốn giá trị này chắc chắn sẽ bắt được lỗi.

Quy tắc 3-value (Three-Value BVA)

Biến thể chặt chẽ hơn, được nhiều tài liệu ISTQB hiện đại khuyến nghị. Với mỗi biên, bạn test 3 giá trị: giá trị ngay dưới, giá trị tại biên, và giá trị ngay trên.

Với biên dưới là 1: test 0, 1, 2. Với biên trên là 100: test 99, 100, 101.

Tổng cộng 6 giá trị. Vì sao cần tới 3 giá trị mỗi biên? Vì 2-value giả định code chỉ mắc lỗi off-by-one đơn giản. Nhưng có những lỗi tinh vi hơn — ví dụ dev dùng nhầm == thay vì >=, khiến chỉ đúng một điểm bị lỗi. 3-value phủ được nhiều dạng lỗi hơn, đổi lại tốn thêm test case. Trong thực chiến, bạn chọn 2-value khi tài nguyên hạn hẹp và rủi ro thấp, chọn 3-value cho các miền quan trọng như tính tiền, tính tuổi, giới hạn giao dịch.

Mối quan hệ với EP — dùng chung, không thay thế

Đừng bao giờ coi BVA và EP là hai lựa chọn loại trừ nhau. Chúng đi cặp. Quy trình chuẩn là: dùng EP để tìm ra các lớp, rồi dùng BVA để tìm ra các biên của từng lớp. EP cho bạn "đại diện giữa lớp" (ví dụ số 50 cho lớp [1,100]), còn BVA cho bạn "đại diện tại biên" (1, 100 và các giá trị sát biên). Kết hợp lại, bạn có một bộ test vừa gọn vừa phủ được cả phần thân lẫn phần rìa của mỗi lớp.

Biên không chỉ là số

Một sai lầm của người mới là nghĩ BVA chỉ áp dụng cho số nguyên. Thực ra biên tồn tại ở nhiều dạng dữ liệu:

  • Độ dài chuỗi: mật khẩu yêu cầu 8–20 ký tự → biên là 8 và 20 ký tự.
  • Ngày tháng: khuyến mãi áp dụng từ 01/06 đến 30/06 → biên là hai ngày đầu và cuối, cộng thêm 31/05 và 01/07.
  • Dung lượng file: upload tối đa 10 MB → biên là đúng 10 MB, 10 MB trừ 1 byte, và 10 MB cộng 1 byte.
  • Thời gian/timeout: phiên đăng nhập hết hạn sau 30 phút → biên tại phút thứ 30.

Tình huống thực tế

Ví dụ 1 — Lỗi off-by-one khiến khách 18 tuổi không mở được ví điện tử

Một ví điện tử giả định ở Việt Nam, tạm gọi là VíXanh, có quy định pháp lý: người dùng phải đủ 18 tuổi mới được mở tài khoản định danh eKYC. Đội dev triển khai kiểm tra tuổi dựa trên ngày sinh nhập vào.

Tester tên Lan áp dụng BVA. Cô xác định biên là 18. Theo quy tắc 3-value quanh biên tuổi 18, cô chuẩn bị các ca test: người 17 tuổi 364 ngày (chưa đủ), người đúng 18 tuổi tròn ngày hôm nay, và người 18 tuổi 1 ngày.

Kết quả: người 18 tuổi 1 ngày mở được. Người 17 tuổi 364 ngày bị từ chối đúng. Nhưng người đúng 18 tuổi tròn ngày hôm nay lại bị hệ thống báo "Chưa đủ tuổi". Đào vào code, hóa ra dev viết if (age > 18) thay vì if (age >= 18). Với cách viết đó, phải qua sinh nhật 19 tuổi mới hợp lệ — một lỗi có thể khiến hàng nghìn khách hàng đúng độ tuổi bị chặn.

Bài học: nếu Lan chỉ test theo EP với một người "khoảng 25 tuổi" (đại diện lớp hợp lệ) và một người "15 tuổi" (đại diện lớp không hợp lệ), bug này sẽ không bao giờ lộ. Chỉ có việc chạm đúng vào con số biên 18 mới phơi bày nó. Đây là ví dụ kinh điển cho câu "off-by-one sống ở biên".

Ví dụ 2 — Miễn phí ship tại Shopee/Lazada khi đơn "từ 300.000đ"

Một sàn thương mại điện tử (bối cảnh tương tự Shopee hay Lazada) chạy chương trình: đơn hàng từ 300.000đ trở lên được miễn phí vận chuyển. Biên ở đây là 300.000đ.

Tester áp dụng 2-value BVA quanh biên: test đơn 299.999đ (phải tính phí ship) và đơn 300.000đ (phải miễn phí ship). Để chắc hơn, anh thêm giá trị 300.001đ.

Khi chạy, đơn 300.000đ vẫn bị tính phí ship 25.000đ. Nguyên nhân: hàm khuyến mãi viết if (total > 300000), trong khi marketing quảng cáo là "từ 300.000đ". Đây là lỗi vừa gây thiệt cho khách, vừa tạo rủi ro pháp lý về quảng cáo sai. Đáng nói là lỗi này về mặt tiền chỉ lệch đúng 1 đồng ở ranh giới, nhưng số khách đặt đơn đúng mốc tròn 300.000đ (vì họ cố mua cho đủ để được free ship) lại rất đông — nghĩa là bug tần suất cao.

Bài học: biên thường trùng với các con số "tròn, đẹp" mà marketing hay chọn (300k, 500k, 1 triệu). Chính vì tròn nên khách hàng có xu hướng dồn về đúng mốc đó. Bug ở biên vì thế không phải "hiếm gặp" mà thường "đụng ngay tập khách đông nhất". Đừng bao giờ bỏ qua giá trị đúng bằng biên.

Ví dụ 3 — Ô nhập mã OTP và biên độ dài chuỗi

Một app ngân hàng yêu cầu nhập mã OTP đúng 6 chữ số. Ở đây lớp hợp lệ chỉ có một độ dài duy nhất: 6. Biên độ dài là 6 ở cả hai phía.

Tester áp dụng BVA cho độ dài chuỗi: nhập OTP có 5 ký tự, 6 ký tự, và 7 ký tự. Cô phát hiện: với 5 ký tự, nút "Xác nhận" vẫn sáng và gửi request lên server (đáng lẽ phải bị chặn ở client với thông báo "Mã chưa đủ 6 số"). Với 7 ký tự, ô input cho gõ tràn và chỉ cắt lấy 6 số đầu một cách âm thầm — khiến khách gõ nhầm mà không biết.

Bài học: BVA áp dụng cho độ dài chứ không chỉ giá trị số. Với các trường có độ dài cố định (OTP, CMND/CCCD 12 số, số điện thoại 10 số), luôn test các độ dài sát biên: thiếu 1, đúng, thừa 1. Đây là mảnh đất màu mỡ để tìm lỗi validation.

Hướng dẫn từng bước

Đây là quy trình bạn có thể áp dụng cho bất kỳ trường đầu vào nào:

Bước 1 — Xác định miền đầu vào có thứ tự. Trường này nhận dữ liệu gì? Số, ngày, độ dài chuỗi, dung lượng? BVA chỉ áp dụng cho dữ liệu có thứ tự (so sánh lớn/nhỏ được). Với dữ liệu rời rạc không thứ tự (ví dụ chọn "Nam/Nữ/Khác"), BVA không phù hợp — dùng EP hoặc Decision Table.

Bước 2 — Xác định các lớp tương đương (dùng EP). Ví dụ ô "tuổi" cho phép 18–65: có lớp không hợp lệ dưới (<18), lớp hợp lệ [18, 65], lớp không hợp lệ trên (>65).

Bước 3 — Tìm biên của mỗi lớp hợp lệ. Ở đây là 18 và 65. Ghi rõ đơn vị nhỏ nhất (đối với số nguyên là 1, đối với tiền VND thường là 1 đồng, đối với dung lượng có thể là 1 byte).

Bước 4 — Chọn quy tắc 2-value hay 3-value. Rủi ro cao (tiền, tuổi pháp lý, giới hạn giao dịch) → 3-value. Rủi ro thấp → 2-value.

Bước 5 — Sinh các giá trị test. Với 3-value quanh biên 18: 17, 18, 19. Quanh biên 65: 64, 65, 66. Đừng quên biên của các lớp không hợp lệ nếu chúng cũng có ý nghĩa.

Bước 6 — Kết hợp với đại diện giữa lớp từ EP. Thêm một giá trị giữa như 40 để chắc chắn phần thân lớp cũng đúng.

Bước 7 — Ghi rõ kết quả kỳ vọng cho từng giá trị. Đây là bước quan trọng nhất và hay bị bỏ qua. Với mỗi giá trị biên, viết chính xác hệ thống phải làm gì (chấp nhận hay báo lỗi, thông báo cụ thể ra sao). Không có kết quả kỳ vọng thì test case vô nghĩa.

Lỗi thường gặp & mẹo

Chỉ test biên hợp lệ, quên biên không hợp lệ. Nhiều tester test 1 và 100 nhưng quên 0 và 101. Chính giá trị "ngay bên kia biên" mới bắt được lỗi < vs <=. Luôn test cả hai phía của mỗi biên.

Nhầm đơn vị nhỏ nhất. Với tiền VND, giá trị sát biên của 300.000 là 299.999, không phải 299.999,99 (vì VND không có phần lẻ). Với USD thì lại là 299.99. Với ngày, "ngay dưới" 01/06 là 31/05, không phải 30/05. Xác định sai đơn vị khiến bạn test hụt biên.

Bỏ qua biên ẩn do kiểu dữ liệu. Một trường "số lượng" kiểu integer 32-bit có biên kỹ thuật tại 2.147.483.647. Nhập một số lớn hơn có thể gây tràn số (overflow) và ra kết quả âm. Ngoài biên nghiệp vụ, hãy để mắt tới biên kỹ thuật: giá trị 0, số âm, chuỗi rỗng, giá trị max của kiểu dữ liệu.

Quên biên ở đầu ra, không chỉ đầu vào. BVA cũng áp dụng cho output. Ví dụ một báo cáo hiển thị tối đa 50 dòng mỗi trang — hãy test tập dữ liệu có đúng 49, 50, 51 bản ghi để xem phân trang có đúng ở biên không.

Mẹo — vẽ trục số. Khi bối rối, hãy vẽ một trục số nằm ngang, đánh dấu các biên bằng vạch đứng, ghi lớp hợp lệ/không hợp lệ ở từng đoạn. Nhìn hình, bạn sẽ thấy ngay mình cần chấm những điểm nào. Đây là mẹo cực hiệu quả khi giải bài thi ISTQB.

Mẹo — biên thường trùng con số marketing. Như ví dụ free ship, các mốc "tròn đẹp" là nơi khách hàng dồn về đông nhất. Ưu tiên test biên tại các con số này vì bug ở đó có tác động thực tế lớn.

Bài tập thực hành

Bài 1. Một website đặt vé xem phim (bối cảnh như CGV hoặc Galaxy) cho phép mua từ 1 đến 8 vé trong một giao dịch. Hãy liệt kê đầy đủ các giá trị test theo quy tắc 2-value BVA3-value BVA. Với mỗi giá trị, ghi rõ kết quả kỳ vọng.

Bài 2. Một chương trình khuyến mãi giảm giá theo bậc: đơn dưới 500.000đ không giảm; đơn từ 500.000đ đến dưới 2.000.000đ giảm 10%; đơn từ 2.000.000đ trở lên giảm 20%. Xác định tất cả các biên, rồi liệt kê giá trị test 2-value cho từng biên (nhớ đơn vị nhỏ nhất là 1 đồng). Bạn tìm được bao nhiêu biên?

Bài 3. Một ô nhập "tên đăng nhập" yêu cầu độ dài 6 đến 15 ký tự. Hãy áp dụng BVA cho độ dài chuỗi và liệt kê các trường hợp cần test. Ngoài ra, hãy nghĩ thêm 2 biên ẩn (gợi ý: chuỗi rỗng và chuỗi có ký tự khoảng trắng ở đầu).

Bài 4 (nâng cao). Một tính năng đặt lịch hẹn chỉ cho phép chọn ngày từ hôm nay đến 30 ngày sau. Giả sử hôm nay là 27/06/2026. Hãy xác định hai biên ngày và viết ra các giá trị test 3-value quanh mỗi biên (dưới dạng ngày cụ thể).

Sau khi làm xong, hãy tự đối chiếu: bạn có test cả giá trị đúng tại biên lẫn ngay bên kia biên không? Có ghi rõ kết quả kỳ vọng cho từng ca không? Nếu thiếu, đó chính là chỗ bug hay lọt qua.

Tóm tắt

Boundary Value Analysis là kỹ thuật săn bug ở đúng nơi chúng ẩn náu nhiều nhất: tại ranh giới của các lớp tương đương. Nó bổ sung cho EP chứ không thay thế — EP tìm lớp, BVA tìm biên của lớp. Hãy nhớ ba điều cốt lõi:

  • Bug thích trốn ở biên vì đó là nơi dev dễ nhầm < với <= — lỗi off-by-one kinh điển.
  • 2-value test giá trị tại biên và ngay bên kia biên (4 giá trị cho một miền hai đầu); 3-value thêm giá trị sát trong biên (6 giá trị), chặt hơn nhưng tốn hơn — chọn theo rủi ro.
  • Biên không chỉ là số: độ dài chuỗi, ngày tháng, dung lượng file, timeout đều có biên; và đừng quên biên không hợp lệ, biên kỹ thuật, cùng biên ở cả đầu ra.
Khi bạn thành thạo BVA, bạn sẽ nhìn mọi ô nhập liệu bằng con mắt khác: không còn hỏi "giá trị hợp lệ là gì" mà hỏi "ranh giới nằm ở đâu, và điều gì xảy ra ngay tại đó". Đó chính là tư duy của một tester biết cách tìm bug với ít test case nhất.