Boundary Value Analysis Variations: 2-Point, 3-Point, Robust, and Worst-Case BVA
Boundary value analysis (BVA) isn't a single technique — it's a family of related methods with different coverage philosophies. The version you learned in your testing certification is probably 2-point BVA: test at the boundary and just inside it. But 3-point BVA, robust BVA, and worst-case BVA each catch different bugs.
Understanding the variants lets you choose the right level of rigor for the risk level of the feature.
The Two Underlying Bugs BVA Targets
Before covering the variants, the motivation:
Off-by-one errors: A condition written as if (x < 100) when it should be if (x <= 100). The incorrect boundary is exactly at the "interesting" value. Testing at 99, 100, and 101 catches this; testing at 50 and 150 doesn't.
Missing range handling: A system that accepts 1–100 should reject 0 and 101. If error handling is only written for the common case and not the edge, boundary testing finds the gap.
Both bugs concentrate at boundaries. BVA exploits this by testing densely near transitions.
2-Point BVA: The Basic Version
For a valid range [min, max], 2-point BVA tests:
min(on the lower boundary)max(on the upper boundary)
And optionally:
min - 1(just below lower boundary)max + 1(just above upper boundary)
For a field accepting 1–100:
- Test: 1, 100 (valid boundaries)
- Test: 0, 101 (invalid boundaries)
Some sources define 2-point BVA as testing only the boundaries themselves (min, max). Others include the just-outside values. The distinction matters:
- Testing only
minandmax: verifies the extremes work - Also testing
min - 1andmax + 1: verifies the rejections work
For most purposes, test all four: min - 1, min, max, max + 1.
Example: Age validation (18–65)
| Value | Category | Expected |
|---|---|---|
| 17 | Below minimum | Reject |
| 18 | Lower boundary | Accept |
| 65 | Upper boundary | Accept |
| 66 | Above maximum | Reject |
2-point BVA: 4 test cases. Fast, covers the most common boundary bugs.
3-Point BVA: The Next Step
3-point BVA adds a value "just inside" each boundary: min, min + 1, max - 1, max.
For age validation (18–65):
| Value | Category | Expected |
|---|---|---|
| 17 | Just below minimum | Reject |
| 18 | Lower boundary | Accept |
| 19 | Just inside lower boundary | Accept |
| 64 | Just inside upper boundary | Accept |
| 65 | Upper boundary | Accept |
| 66 | Just above maximum | Reject |
3-point BVA: 6 test cases (vs. 4 for 2-point).
When does 3-point add value?
3-point BVA catches a specific class of off-by-one that 2-point misses:
Bug: Code treats min as invalid (should be valid). The system correctly handles min + 1 and above.
2-point tests min and finds the bug. But 3-point also tests min + 1, confirming the "just inside" value works. This distinction matters when the boundary behavior is complex — for example, if min has special semantics ("free tier") and min + 1 is a different tier.
Use 3-point BVA when:
- The boundary itself has special semantics (not just "valid vs. invalid")
- You need to verify correct behavior on both sides of each boundary
- The system handles the boundary differently from values just inside it
Use 2-point BVA (4 values) when:
- You want minimal test cases for high-level risk coverage
- The boundary is a simple valid/invalid transition with no special semantics at the boundary value itself
Robust BVA: Extending to Invalid Partitions
Standard BVA tests boundaries of valid ranges. Robust BVA extends this to invalid ranges too — testing values outside the valid range to verify error handling.
For age validation (18–65), robust BVA adds:
- Min extreme: 0 or negative (far outside valid range)
- Below minimum: 17 (just outside)
- Lower boundary: 18
- [Normal valid values]
- Upper boundary: 65
- Above maximum: 66 (just outside)
- Max extreme: 999 or MAX_INT (far outside valid range)
Robust BVA adds invalid extremes to the test set.
Why invalid extremes matter
The lower and upper extremes of invalid input often trigger different bugs than values just outside the boundary:
- Value 66 for age 65 max: probably triggers "above maximum" error handling
- Value 9999 for age 65 max: might trigger integer overflow, database column limit, or UI rendering failure for a 4-digit number
Applications often validate the "expected" invalid range but fail to handle extreme values. Robust BVA tests the entire invalid partition, not just the region adjacent to the valid range.
Implementation example
# Robust BVA for age field (valid: 18-65)
robust_bva_cases = [
# Invalid extremes
(0, "zero"),
(-1, "negative"),
(-999999, "large negative"),
# Below minimum boundary region
(17, "just below min"),
(18, "lower boundary"), # valid
(19, "just inside min"), # valid
# Upper boundary region
(64, "just inside max"), # valid
(65, "upper boundary"), # valid
(66, "just above max"),
# Invalid extremes
(100, "well above max"),
(999, "large value"),
(2147483647, "max int32"),
]Robust BVA roughly doubles the number of test cases compared to standard BVA. Use it for high-risk inputs (financial values, security-relevant fields, inputs that directly map to system resources).
Worst-Case BVA: Multiple Variables
Standard BVA tests one variable at a time, holding others at nominal values. Worst-case BVA combines boundary values across multiple variables simultaneously.
Single variable vs. worst-case
For a function accepting two inputs (a: 1–10, b: 1–5):
Normal BVA (each variable independently):
- a: 0, 1, 10, 11 (b held at nominal = 5)
- b: 0, 1, 5, 6 (a held at nominal = 5) Total: 8 test cases (minus duplicates)
Worst-case BVA (all combinations of boundary values):
For each variable, define boundary value set = {min-1, min, max, max+1}
Combine across variables:
| a | b | Expected |
|---|---|---|
| 0 | 0 | Both invalid |
| 0 | 1 | a invalid |
| 0 | 5 | a invalid |
| 0 | 6 | Both invalid |
| 1 | 0 | b invalid |
| 1 | 1 | Both at min (valid) |
| 1 | 5 | Both at max (valid) |
| 1 | 6 | b invalid |
| 10 | 0 | b invalid |
| 10 | 1 | Both at min (valid) |
| 10 | 5 | Both at max (valid) |
| 10 | 6 | b invalid |
| 11 | 0 | Both invalid |
| 11 | 1 | a invalid |
| 11 | 5 | a invalid |
| 11 | 6 | Both invalid |
Full worst-case: 4^n test cases for n variables with 4 boundary values each.
For 2 variables: 16 cases. For 3 variables: 64 cases. For 5 variables: 1024 cases. Combinatorial explosion makes full worst-case BVA impractical beyond 2–3 variables.
Strong BVA: reduced combination
Strong BVA tests each boundary value of each variable against boundary values of all others, but not every combination:
For a: {min-1, min, max, max+1} For b: {min-1, min, max, max+1}
Strong BVA selects: for each (a_boundary, b_boundary) pair where at least one is at its extreme. This reduces to a manageable set while still catching cross-variable failures.
When worst-case BVA applies
Use worst-case BVA when:
- Multiple inputs interact in complex ways (area calculation: width × height, where overflow is possible)
- Financial calculations combine multiple values (principal × rate × time)
- Security checks combine multiple user-supplied values
For most input validation, normal BVA testing each variable independently is sufficient. Worst-case BVA is for functions where multiple boundary conditions occurring simultaneously create distinct failure modes.
Choosing the Right BVA Variant
| Risk Level | Recommended Variant | Test Cases per Range |
|---|---|---|
| Low | 2-point BVA | 4 |
| Medium | 3-point BVA | 6 |
| High | Robust BVA | 8–10 |
| Critical (multi-variable) | Worst-case BVA | 16+ |
Risk factors that increase the variant level:
- Financial impact of incorrect boundary handling
- Security relevance (authentication, authorization, resource access)
- Complex interactions between variables
- History of boundary bugs in this component
- External input from untrusted sources
Apply robust or worst-case BVA to the 20% of inputs with highest business impact. Apply 2-point BVA to the rest. Spending the same rigor on every input wastes time where it doesn't matter and prevents adequate coverage where it does.
Boundary Values for Different Data Types
Integer and float ranges
Covered above. For floating point, include:
- Boundary values as defined
boundary ± epsilon(smallest representable increment)- Infinity and NaN for math-intensive code
Date ranges
For "date must be between 2020-01-01 and 2025-12-31":
- Day before start: 2019-12-31
- Start date: 2020-01-01
- Day after start: 2020-01-02
- Day before end: 2025-12-30
- End date: 2025-12-31
- Day after end: 2026-01-01
- Edge cases: Feb 28/29, Dec 31, Jan 1 (year boundaries)
String length ranges
For "string must be 1–255 characters":
- Length 0 (empty string)
- Length 1 (minimum)
- Length 254 (just inside maximum)
- Length 255 (maximum)
- Length 256 (just above maximum)
- Length 65535 (far above maximum — tests database/buffer limits)
Summary
The BVA variant determines coverage depth. 2-point BVA is the starting point: boundaries and their immediate neighbors. 3-point BVA adds interior boundary values for complex semantics. Robust BVA covers invalid partitions fully. Worst-case BVA addresses multi-variable interactions.
For most testing, 2-point BVA applied consistently beats any variant applied inconsistently. Start with 2-point everywhere, upgrade to robust or worst-case for your highest-risk inputs.
The fundamental insight remains: bugs concentrate at boundaries. Whatever variant you use, test there.