Boundary value analysis: 30 worked examples
A signup form says "you must be 18 or older". A tester types 25, sees the form pass, and moves on. Two weeks later a 17-year-old creates an account, because the code says age > 17 in one place and age >= 18 in another, and only one of them runs.
Nobody typed 17. Nobody typed 18. That is the whole bug.
Boundary value analysis is the habit of always typing those two numbers.
Short version
- A boundary is the point where behaviour changes from allowed to blocked.
- Bugs cluster at boundaries because programmers mix up
<and<=. - For each boundary, test three values: one below, the boundary itself, one above.
- Boundaries hide in dates, page counts, file sizes, and character limits, not just numbers.
- The 30 examples below give you exact values you can copy into test cases today.
What a boundary actually is
A boundary is the exact point where a system changes its answer.
If a field accepts 1 to 100, then 1 and 100 are boundaries. Below 1 the system says no. Above 100 the system says no. At 1 and 100 it says yes.
Programmers write these rules with comparison operators: < (less than), <= (less than or equal to), > (greater than), >= (greater than or equal to). Choosing the wrong one shifts the boundary by exactly one. This is called an off-by-one error, and it is one of the most common bugs in software.
Boundary value analysis is a black box technique. Black box means you test only what the system does from the outside, without reading the code.
The three-value rule
For every boundary, test three values:
- The value just below the boundary
- The boundary value itself
- The value just above the boundary
For a minimum age of 18, that is 17, 18, and 19.
"Just below" and "just above" depend on the smallest step the field allows. For whole numbers the step is 1. For money it is usually 0.01. For dates it is one day. For timestamps it might be one second or one millisecond.
Bad: "Test the age field with valid and invalid ages."
Good: "Enter 17 — expect the error
You must be 18 or older. Enter 18 — expect the form to submit. Enter 19 — expect the form to submit."
The second version can be run by anyone and cannot be argued about.
Numbers and age fields
Six worked examples. In each row, run every value listed.
| Rule | Values to test | What you are checking |
|---|---|---|
| Age must be 18 or older | 17, 18, 19 | The >= vs > mix-up |
| Age must be under 120 | 119, 120, 121 | Whether 120 itself is allowed |
| Quantity between 1 and 10 | 0, 1, 2, 9, 10, 11 | Both ends of the range |
| Rating from 1 to 5 stars | 0, 1, 5, 6 | Zero stars often slips through |
| Discount percentage 0 to 100 | -1, 0, 1, 99, 100, 101 | Negative values and over 100 |
| Team seats, minimum 3 | 2, 3, 4 | Downgrade below the plan minimum |
Zero and negative numbers deserve extra attention. A quantity of 0 in a cart often removes the item, which may not be intended. A quantity of -1 can produce a negative order total.
Dates and times
Dates have more boundaries than any other field type, because the calendar itself is full of them.
| Rule | Values to test | What you are checking |
|---|---|---|
| Booking must be a future date | Yesterday, today, tomorrow | Whether "today" counts as future |
| Trial ends after 14 days | Day 13, day 14, day 15 | The final day of access |
| Report range: start before end | Start = end, start = end + 1 day | Same-day ranges |
| Month rollover | 31 Jan, 1 Feb, 28 Feb, 1 Mar | Month lengths |
| Leap year | 28 Feb 2028, 29 Feb 2028, 1 Mar 2028 | Leap day handling |
| Year rollover | 31 Dec 2026 23:59, 1 Jan 2027 00:00 | Year and week-number logic |
Add one more: set your machine to a timezone like Pacific/Auckland (UTC+12) and repeat the "future date" test. A date that is tomorrow for you may still be today on the server.
Pagination and lists
Pagination bugs are boundary bugs almost every time. Assume 10 items per page.
| Rule | Values to test | What you are checking |
|---|---|---|
| Empty list | 0 items | The empty state renders at all |
| One page exactly | 9, 10, 11 items | Whether a second page appears at 11, not 10 |
| Last page | 20 items, then open page 2 | Off-by-one in the final page |
| Page number out of range | Page 0, page 1, page 999 | ?page=0 and ?page=999 in the URL |
| Deleting the last item on a page | Delete item 11 of 11 while on page 2 | The empty page 2 problem |
| Sorting boundary | Two items with identical timestamps | Stable ordering |
Try page numbers directly in the address bar, for example https://staging.example.com/orders?page=0. Many apps guard the buttons but not the URL, and you get a blank screen or a crash such as TypeError: Cannot read properties of undefined (reading 'map').
File uploads and sizes
Assume the limit is "images up to 5 MB".
| Rule | Values to test | What you are checking |
|---|---|---|
| Maximum size | 4.9 MB, 5.0 MB, 5.1 MB | Whether exactly 5 MB is allowed |
| Empty file | A 0 KB file | Zero-length handling |
| Minimum dimensions, 200x200 px | 199x199, 200x200, 201x201 | Dimension checks |
| Filename length | 254, 255, 256 characters | Filesystem name limits |
| Number of files at once | 9, 10, 11 files | Batch upload limits |
| Total upload quota | 1 byte under quota, exactly at quota, 1 byte over | Quota maths |
Note the difference between 5 MB counted as 5,000,000 bytes and 5 MB counted as 5,242,880 bytes. Files between those two sizes pass one check and fail the other. If a bug appears in that gap, capture the console and network response along with the file size — a tool like Crosscheck records the failing request and browser details automatically when you report from the page.
Money and currency limits
Money uses two decimal places, so the smallest step is 0.01.
| Rule | Values to test | What you are checking |
|---|---|---|
| Minimum payment of 1.00 | 0.99, 1.00, 1.01 | The minimum charge rule |
| Free shipping over 50.00 | 49.99, 50.00, 50.01 | "Over" versus "50 or more" |
| Refund up to the amount paid | Paid 20.00, refund 19.99, 20.00, 20.01 | Over-refunding |
| Card limit of 9,999.99 | 9,999.98, 9,999.99, 10,000.00 | Field width and gateway limits |
| Zero-amount order | 0.00 after a 100% discount code | Payment of nothing |
| Rounding | 0.005, 0.015, 33.335 | Half-up versus half-even rounding |
Rounding deserves a test of its own. Split 10.00 three ways and check the parts add back to 10.00 and not 9.99.
Text length limits
Six more, using a 255-character bio field as the example.
| Rule | Values to test | What you are checking |
|---|---|---|
| Maximum length | 254, 255, 256 characters | Whether the limit truncates or errors |
| Minimum length, 8-character password | 7, 8, 9 characters | Password rules |
| Empty and whitespace | "" and " " (three spaces) | Whether spaces count as content |
| Multi-byte characters | 255 emoji, 255 Chinese characters | Bytes counted instead of characters |
| Username uniqueness | qa-user and QA-User | Case sensitivity at the edge |
| Trailing whitespace | [email protected] with a trailing space | Trimming before validation |
The multi-byte row catches a real and frequent bug. A field limited to 255 bytes will reject about 63 emoji, even though the user typed far fewer than 255 characters.
How to turn these into test cases
- List every field and rule in the feature.
- Write the rule as a range, for example "1 to 10 inclusive".
- Mark the boundary at each end.
- Work out the smallest step for that field: 1, 0.01, one day, one byte.
- Write three test values per boundary: below, at, above.
- Write the expected result for each value before you run it.
Step 6 is the one people skip. If you decide the expected result after seeing the screen, you will accept whatever the software does.
Mistakes that make this technique fail
Testing only the middle. Entering 50 in a 1-to-100 field proves almost nothing. The middle is where code is most likely to be correct.
Testing only the invalid side. A rule that wrongly rejects 18-year-olds is as bad as one that wrongly accepts 17-year-olds.
Ignoring the client-server split. The browser may block 17 while the API accepts it. Send the request directly with curl or the network tab.
Forgetting that the step is not always 1. For a price field, "just below 50.00" is 49.99, not 49.
Frequently asked questions
What is the difference between boundary value analysis and equivalence partitioning?
Equivalence partitioning groups inputs that should behave the same way and tests one value from each group. Boundary value analysis tests the edges between those groups. Most teams use both together.
Should I use two values or three at each boundary?
Three is the standard and it is safer. Two-value testing only checks the boundary and one neighbour, so it can miss a rule that is shifted the other way. Use two only when test runs are expensive.
Do I need boundary tests if we have automated unit tests?
Unit tests are the best place for boundary values, because they run fast and cover many values cheaply. Still test the boundaries manually once through the interface, since validation often lives in more than one layer.
How do I find boundaries when there is no written specification?
Read the error messages, the placeholder text, and the database column types. A VARCHAR(255) column and a message saying "must be at least 8 characters" both name a boundary.
Is boundary testing useful for dropdowns and checkboxes?
Not directly, since those inputs have no range. Use equivalence partitioning or decision tables for them, and save boundary analysis for fields with ordered values such as numbers, dates, and lengths.




