What Is Boundary Value Analysis?

Boundary Value Analysis (BVA) is a black-box test design technique that focuses on testing values at the edges of equivalence classes. While Equivalence Partitioning tells you which groups to test, BVA tells you where within those groups defects are most likely to hide.

Why Boundaries Matter

Studies consistently show that a disproportionate number of software defects occur at boundary values. The reason is simple: developers write conditions like if (age >= 18) or if (quantity <= 100), and off-by-one errors (> vs >=, < vs <=) are among the most common coding mistakes.

# Intended: accept ages 18 and above
if age > 18:      # Bug! Rejects 18-year-olds
    allow_access()

# Correct:
if age >= 18:
    allow_access()

This single-character difference (> vs >=) causes a defect that only manifests at the boundary value 18. Testing with age=25 would never catch it.

Two-Value BVA (Standard)

The most common approach tests two values per boundary: the boundary itself and the value just outside it.

For a valid range of 1 to 100:

graph LR A["0 ❌"] --- B["1 ✅"] --- C["... valid ..."] --- D["100 ✅"] --- E["101 ❌"] style A fill:#ffcccc style B fill:#ccffcc style D fill:#ccffcc style E fill:#ffcccc
BoundaryTest ValuesExpected
Lower0 (just below)Invalid
Lower1 (boundary)Valid
Upper100 (boundary)Valid
Upper101 (just above)Invalid

4 test cases cover both boundaries.

Three-Value BVA (Rigorous)

For higher-risk systems, test three values per boundary: just below, the boundary, and just above.

For the same range 1 to 100:

BoundaryTest ValuesExpected
Lower0Invalid
Lower1Valid
Lower2Valid
Upper99Valid
Upper100Valid
Upper101Invalid

6 test cases for more thorough coverage. The additional values (2 and 99) catch defects where the boundary condition is off by more than one.

BVA for Different Data Types

Integers: Straightforward — boundary ± 1.

  • Range 1-10: test 0, 1, 10, 11

Floating-point: Use the smallest meaningful increment.

  • Range 0.0-1.0: test -0.01, 0.0, 1.0, 1.01 (or -0.001, 0.0, 1.0, 1.001 depending on precision)

Strings (length): Test at length boundaries.

  • Username 3-20 chars: test 2 chars, 3 chars, 20 chars, 21 chars

Dates: Test at date boundaries.

  • Valid dates Jan 1 - Dec 31: test Dec 31 of previous year, Jan 1, Dec 31, Jan 1 of next year

Collections (size): Test at count boundaries.

  • Cart items 1-50: test 0 items, 1 item, 50 items, 51 items

Combining EP and BVA

These two techniques are natural partners. EP identifies the partitions; BVA focuses on their edges.

Example: Shipping cost by weight

Weight (kg)Shipping
0.1 – 1.0$5
1.01 – 5.0$10
5.01 – 20.0$20
> 20.0$35

EP representatives (middle of each class): 0.5, 3.0, 12.0, 25.0

BVA values (at boundaries): 0.09, 0.1, 1.0, 1.01, 5.0, 5.01, 20.0, 20.01

Combined, you get thorough coverage with just 12 test cases.

graph LR subgraph "$5 zone" A[0.09❌] --- B[0.1✅] --- C[0.5] --- D[1.0✅] end subgraph "$10 zone" D --- E[1.01✅] --- F[3.0] --- G[5.0✅] end subgraph "$20 zone" G --- H[5.01✅] --- I[12.0] --- J[20.0✅] end subgraph "$35 zone" J --- K[20.01✅] --- L[25.0] end

Advanced BVA Techniques

Multi-Dimensional Boundaries

When a system has multiple interacting parameters, boundaries exist in multiple dimensions. Consider a pricing engine:

  • Quantity: 1-1000
  • Unit price: $0.01-$9999.99

The interesting boundaries aren’t just the individual parameter edges but the combinations:

TestQuantityUnit PriceTotalWhy
11$0.01$0.01Minimum possible total
21000$9999.99$9,999,990Maximum possible total
31$9999.99$9999.99Max price, min quantity
41000$0.01$10.00Min price, max quantity

Internal Boundaries

Not all boundaries are at the edges of valid/invalid ranges. Internal boundaries separate different processing paths within the valid range:

def calculate_tax(income):
    if income <= 10000:
        return income * 0.10
    elif income <= 50000:
        return 1000 + (income - 10000) * 0.20
    else:
        return 9000 + (income - 50000) * 0.30

Internal boundaries at $10,000 and $50,000 are just as important as the overall valid range boundaries. Test: $9,999, $10,000, $10,001, $49,999, $50,000, $50,001.

Implicit Boundaries

Some boundaries aren’t in the specification but exist in the implementation:

  • Integer overflow: 2,147,483,647 (max 32-bit signed int)
  • Array limits: 0-indexed vs 1-indexed collections
  • Empty/null: The boundary between “something” and “nothing”
  • Precision limits: Floating-point comparison issues at very small differences

BVA for Time-Based Systems

Time boundaries are particularly tricky:

ScenarioBoundary Values
Session timeout (30 min)29:59, 30:00, 30:01
Daily batch job (midnight)23:59:59, 00:00:00, 00:00:01
Leap year (Feb 28/29)Feb 28, Feb 29, Mar 1
DST transition01:59, 02:00 (spring forward), 01:00 (fall back)

Exercise: BVA for a Password Policy

Scenario: A system enforces this password policy:

  • Length: 8-64 characters
  • Must contain at least 1 uppercase letter
  • Must contain at least 1 digit
  • Must contain at least 1 special character (!@#$%^&*)

Task: Identify all boundary values for the length requirement and design test cases using three-value BVA. Then identify how the character-type requirements create additional boundaries.

Hint

For length, the boundaries are 8 (minimum) and 64 (maximum). Three-value BVA means testing 7, 8, 9 at the lower boundary and 63, 64, 65 at the upper.

For character types, the boundary is between 0 and 1 occurrence of each required type. Think about a password with exactly 0 uppercase letters vs exactly 1.

Solution

Length BVA (three-value):

#LengthTest ValueExpected
17 charsAa1!xyzReject (too short)
28 charsAa1!xyzwAccept (lower boundary)
39 charsAa1!xyzwqAccept (just above lower)
463 charsAa1! + 59 x’sAccept (just below upper)
564 charsAa1! + 60 x’sAccept (upper boundary)
665 charsAa1! + 61 x’sReject (too long)

Character-type boundaries:

#TestExpected
70 uppercase: aa1!xyzwReject
81 uppercase: Aa1!xyzwAccept
90 digits: Aa!!xyzwReject
101 digit: Aa1!xyzwAccept
110 special: Aa1bxyzwReject
121 special: Aa1!xyzwAccept

Total: 12 test cases covering all boundaries for length and character-type requirements.

Pro Tips

  • Always pair BVA with EP. BVA without EP misses the big picture; EP without BVA misses the most defect-dense areas.
  • Don’t forget zero and empty. Zero items, zero-length strings, and empty collections are boundaries that reveal null pointer exceptions, division by zero, and other common defects.
  • Consider the minimum increment. For integers it’s 1, for currency it might be 0.01, for timestamps it could be 1 second or 1 millisecond. Use the right increment for your domain.
  • Test both sides of every boundary. A boundary has two sides — valid and invalid. Missing either side leaves defects uncovered.
  • In APIs, test boundary values in request parameters, headers, and response handling. Boundaries in API pagination (page=0, page=1, page=maxInt) frequently contain bugs.