Skip to content
beginner Phase 3 · Test Case Design Techniques

Boundary Value Analysis

Test just below, at, and just above limits where off-by-one defects typically hide.

40m
0 problems
Topic Progress 0%

Where Off-by-One Bugs Are Born and How Tests Hunt Them

A file upload allows 'up to 10 MB'. QA tested with 2 MB and 50 MB files — both behaved correctly — and shipped. Users then report that an 11 MB file uploaded fine and corrupted the storage quota accounting. The field validated size < 10 where the requirement said 'up to 10 MB' meaning size <= 10. Classic boundary defect: the code is right in the middle of every range and wrong at its edges, because edges are where the human reading of a specification meets the exactness of a comparison operator.

Why boundaries concentrate defects has a mechanical explanation. Developers write range checks from memory: age > 18 versus age >= 18, loop counters running to n versus n-1, zero-based indexing against one-based specifications. Each is a one-character decision the middle of the range never exercises — if 30 works, > 18 and >= 18 are indistinguishable, and only the value 18 tells them apart. Second, specifications are sloppy at edges: 'up to 10 MB', 'maximum 5 attempts', 'within 30 days' — each phrase forces an operator decision the spec never states, and every such decision is a potential defect. Boundary value analysis makes this systematic.

The template. For a range with minimum min and maximum max, test six values:

min-1, min, min+1, max-1, max, max+1

Age valid [18..65]:   17, 18, 19,  64, 65, 66
File size up to 10:    9, 10, 11   (with 0 and a tiny valid file as the low edge)

Each value has a job. min-1 and max+1 verify rejection of out-of-range input. min and max verify inclusivity — the single most common boundary question. min+1 and max-1 catch off-by-one slips that a wrong operator introduces one step inside the valid range. In practice, testing teams often trim to four values (min-1, min, max, max+1) when execution is expensive, but keep all six when tests are automated — the marginal cost is near zero and off-by-one defects love the +1-inside position.

Finding the boundaries the spec never labels. The richest source of unexamined boundaries is in-between specifications:

Spec phrase Hidden boundaries to test
'up to 10 items in cart' 9, 10, 11 — and the 11th item added while on the 10th (race)
'free shipping over $50' $49.99, $50.00, $50.01 — and tax-inclusive vs exclusive total
'within 30 days for returns' day 29, day 30, day 31 — and time-zone of 'day'
'3 retry attempts' attempts 1, 2, 3, 4 — is the 4th blocked or queued?

The last column of that table is the senior-level habit: every boundary in a stateful context has an interaction — the boundary value reached through an unusual path (item added concurrently, return checked across a time zone) is where boundary defects survive ordinary suites.

In interviews, boundary value analysis is the technique most often requested as a live exercise ('design tests for a field accepting 1-100'). Deliver the six-value template immediately, name inclusivity as the question the min/max pair answers, then add the derived layer — zero, negatives, non-numeric, and empty as the invalid partitions from Equivalence Partitioning — and the interviewer knows you can combine techniques instead of reciting them.

Boundaries Beyond Numbers: Lengths, Dates, Pages, and Collections

The six-value template is taught on numeric fields and then misapplied everywhere else, because the interesting boundaries in real interfaces are lengths, dates, counts, and states. The technique generalizes once you see what each boundary actually measures.

String lengths. A username field says '3-20 characters'. The boundary dimension is character count, with three twists that make string boundaries richer than numeric ones:

Count boundaries:  2, 3, 4   and   19, 20, 21 characters
Content twists:    3 characters as multibyte unicode (emoji = 4 bytes, 1 grapheme)
                   20 characters ending mid-surrogate-pair (splitting a 4-byte emoji)
                   whitespace-only input ('   ' — is it length 3 or empty after trim?)

The multibyte case is a recurring production defect: the database column stores 20 characters, the API counts 20 bytes, and a user with a 7-character emoji name gets rejected by one layer and accepted by another. Byte-vs-character counting is a boundary class of its own, and testing it is a five-case investment that frequently pays out.

Dates and time. A booking window '2026-06-01 to 2026-06-30' has day boundaries (05-31, 06-01, 06-02, 06-29, 06-30, 07-01) plus three hazards: inclusive-endpoint semantics ('through June 30' usually includes that day — verify), time zones (a user in UTC+13 books 'June 30' locally that is June 29 in server time), and month/day rollovers (booking on the 31st for a 30-day month). Leap day (2026 is not a leap year; 2028 is) and daylight-saving transitions belong to this family — a nightly batch job that runs at 02:30 will skip or double-run on DST nights in affected regions.

Pagination and collections. 'Showing 1-20 of 213' hides a small matrix: a result set of exactly 20 (does a second empty page appear?), of 21 (does the last page show 1?), the final page's boundary (item 213 individually removable — does the count and page math update?), and the empty result set (page 1 of 0 — error or graceful empty state?). These boundaries fail far more often than the numeric ones testers obsess over, because pagination logic is written once, quickly, and rarely re-read.

Numeric counts and quotas. The '3 free exports per month' boundary has a fourth dimension: time. Test exports 1, 2, 3, 4 (quota exhaustion behavior), then the reset boundary — the last second of the month, the first of the next, and the user's local month vs server month if they differ. Quota boundaries without reset boundaries are half-tested quotas.

A compact way to carry this in review: when reading any requirement, circle every quantity and ask what is one less, one more, and one at-the-limit — and does 'at the limit' mean in or out? The question list — inclusive or exclusive, bytes or characters, server or local time, empty set or single page — is a reusable boundary audit that works even without a formal test design session, and it is exactly what experienced testers run in their heads during requirement reviews. The formal suites come next; the audit is what finds the boundaries nobody wrote down.

Building the Compact Defect-Rich Suite: EP + BVA Together

Used alone, boundary value analysis covers edges but leaves the interior of each class unverified and the invalid classes unlisted. Combined with equivalence partitioning, it produces the suite design that experienced testers actually ship: partitions for structure, boundaries for precision. The combination has a repeatable five-step form, demonstrated on a coupon field: 'discount codes are 6-10 alphanumeric characters, one active coupon per customer, valid until the stated expiry date'.

Step 1 — partition each input (EP). Coupon code: valid (6-10 alphanumeric), invalid (too short, too long, non-alphanumeric, empty). Active-coupon state: none active, one active. Expiry: before today, today, after today.

Step 2 — mark the boundaries in each partition (BVA). Code length: 5, 6, 7 and 9, 10, 11 characters. Expiry: yesterday, today, tomorrow.

Step 3 — write the case list with expected behavior:

1.  6-char alphanumeric code, no active coupon, expiry +30d  → accepted
2.  5-char code                                              → rejected: too short
3.  11-char code                                             → rejected: too long
4.  6-char code with '-'                                     → rejected: non-alphanumeric
5.  10-char code (upper bound inside)                        → accepted
6.  coupon with expiry = today                               → accepted (verify inclusive semantics)
7.  coupon with expiry = yesterday                           → rejected: expired
8.  valid code with one coupon already active                → rejected: one-per-customer rule

Step 4 — add the interaction cases. Case 8 is where conditions cross — and once conditions combine, a decision table (the next topic) audits whether every rule combination has a case. If the coupon logic has four independent conditions, the table guarantees the suite does not silently skip 'expired coupon when one is already active'.

Step 5 — automate and measure. Every case above is a cheap API-level test; the full set runs in seconds in CI. This is the practical payoff of doing design technique work before writing tests: the suite is small (eight cases), each case is justified by a named defect class (too-short codes, expired coupons, one-per-customer violations), and the whole thing is defensible in review — 'why 8 cases?' has a precise answer, unlike the defense of an arbitrary 40-case spreadsheet.

The interview exercise pattern for this topic is a spec given cold — 'a search field accepts 1-100 characters, results paginate at 20 per page' — and a request to design tests. Run the five steps visibly: partition (valid/empty/too-long), boundary-mark (0, 1, 2 and 99, 100, 101; plus whitespace-only and multibyte), pagination boundaries (exactly-20 results, 21, empty result set), one or two interaction cases (100-char query that also hits the empty-result path), and state what you deliberately did not test (exhaustive character sets — the field's handling is uniform by content). Naming the omissions with reasons is what separates a designer from a test-typist, and it is the consistent thread of this phase: every technique buys specific defect classes at a specific cost, and the professional skill is matching the purchase to the risk.

Instrumenting boundaries in automation is nearly free: boundary tables are parameterized fixtures where each row carries the input and the expected accept-or-reject outcome, so a spec change to the limit becomes a data edit. One maintenance rule prevents the usual decay: when a boundary moves, grep the suite for the old value — stale boundary constants are the most common source of tests that quietly verify last year's specification. The same grep discipline applies to requirement IDs referenced in assertions: a renamed limit with an unupdated test is a coverage gap wearing the costume of coverage.

Quiz

1. A quantity field accepts 1-100. Which is the complete six-value boundary set?

Question 1 options

2. The spec says 'up to 10 MB' but users report 11 MB files upload successfully. Which defect class does this illustrate, and what should the tests have asked?

Question 2 options

3. A username field accepts 3-20 characters. Which input most likely exposes a boundary defect invisible to ASCII-only tests?

Question 3 options

4. For '3 free exports per month', which test extends boundary analysis correctly?

Question 4 options

Flashcards

Question

What is the boundary value analysis template for a range [min..max], and what does each value verify?

Answer

min-1, min, min+1, max-1, max, max+1. min-1/max+1 verify out-of-range rejection; min/max verify inclusivity (`<` vs `<=` — the most common boundary question); min+1/max-1 catch off-by-one slips one step inside the valid range. Trim to four values only when execution is expensive; keep all six under automation.

Question

Why do off-by-one defects cluster at boundaries instead of the middle of ranges?

Answer

A wrong comparison operator (`<` vs `<=`, `>` vs `>=`, loop to n vs n-1) is indistinguishable at interior values — any two in-range values give the same result — but diverges at exactly the edge values. Specifications also force unstated operator decisions ('up to', 'maximum', 'within'), and every such phrase is a potential operator defect.

Question

Name four hidden boundary classes in interfaces beyond numeric ranges.

Answer

String lengths (count boundaries + multibyte: emoji = 4 bytes/1 grapheme, surrogate-pair splitting, whitespace-only-after-trim); date ranges (endpoint inclusivity, time zones, DST for scheduled jobs, leap days); pagination/collections (exactly one page, N+1 items, last-item removal, empty result set); quotas with time reset (exhaustion path + month-end boundary + local vs server clock).

Question

How do you find boundaries a spec never labels?

Answer

Circle every quantity and constraint phrase and ask: what is one less, one more, and at-the-limit — and is at-the-limit in or out? Then apply the audit list: inclusive or exclusive semantics, bytes vs characters, server vs local time, empty set vs single page, and stateful interactions (boundary reached via concurrent or unusual paths).

Question

Describe the five-step EP+BVA combination workflow.

Answer

(1) Partition each input into valid/invalid classes (EP); (2) mark min/max boundary values inside each partition (BVA); (3) write cases with explicit expected behavior; (4) add interaction cases where conditions combine — audit with a decision table for full rule coverage; (5) automate the whole set at the cheapest level (API tests, seconds in CI) so the small defect-rich suite runs on every build.

Revision Notes

Key Takeaways

  • 1. Off-by-one defects live at edges because wrong operators are indistinguishable at interior values — only boundary values discriminate `<` from `<=`
  • 2. The six-value template verifies rejection, inclusivity, and interior off-by-one; inclusivity (min/max pair) answers the most common boundary question
  • 3. The richest boundaries are unlabeled: string lengths with multibyte counting, date endpoints across time zones, pagination at exactly-N and empty sets, quota resets
  • 4. Boundaries in stateful contexts have interaction cases — the boundary reached via concurrent or unusual paths is where defects survive ordinary suites
  • 5. EP structures the suite and BVA sharpens its edges; automate the combined set at API level so the small defect-rich suite runs on every build

Interview Tips

  • • "Design tests for a field accepting 1-100." — deliver 0,1,2,99,100,101 immediately, explain what each value verifies, then add the invalid partitions (zero, negative, non-numeric, empty) from EP; the combination is the expected senior answer
  • • "Where do off-by-one bugs come from?" — operator decisions at range edges (`<` vs `<=`), unstated spec semantics ('up to', 'maximum'), and zero/one-based conversions; naming the origin shows you debug, not just test
  • • "What boundaries would you test for a date range?" — endpoints plus inclusivity semantics, time zones, DST transitions for scheduled jobs, leap days — then note the interaction cases (booking across the boundary while in a different zone)
  • • "How many boundary cases per field and why?" — six when automated (near-zero marginal cost), four when execution is expensive (min-1, min, max, max+1); stating the trade-off shows you size suites by cost, not by ritual

Cheat Sheet

Boundary Value Analysis

Six-value template: min-1, min, min+1, max-1, max, max+1

Value Verifies
min-1 / max+1 Out-of-range rejection
min / max Inclusivity (< vs <=)
min+1 / max-1 Off-by-one inside the range

Why edges: wrong operators are invisible at interior values; specs ('up to', 'maximum', 'within') force unstated operator decisions.

Hidden boundary classes:

  • Strings: count edges + multibyte (emoji 4 bytes/1 grapheme), surrogate splits, whitespace-only trim
  • Dates: endpoint inclusivity, time zone, DST batch jobs, leap days
  • Pagination: exactly-N results, N+1, last-item removal, empty set
  • Quotas: attempt N vs N+1 + reset boundary (month end, local vs server clock)

Spec-phrase audit: 'up to 10 items' → 9, 10, 11 + concurrent add · 'free shipping over $50' → 49.99/50.00/50.01 + tax-inclusive total · 'within 30 days' → 29/30/31 + which time zone.

EP+BVA workflow: partition → boundary-mark → cases with expected behavior → interaction cases (decision-table audit) → automate at API level (seconds in CI).

Suite justification: 8 named cases, each tied to a defect class — beats an arbitrary 40-case spreadsheet in review.

Continue Learning