Boundary Value Analysis
Bugs love edges. Learn why mistakes cluster at the limits of a rule, how to pick 2-value and 3-value boundary tests, and how to find off-by-one bugs in ages, passwords, dates, money, lists and prices.
An online shop launches a summer promotion: “Free shipping on orders of €50 or more!” It’s tested, it ships, and the first weekend goes well. Then the support inbox fills up. Dozens of customers carefully filled their carts to exactly €50.00, and every single one was charged €4.99 for shipping.
The tester had checked a €35 cart (pays shipping) and an €80 cart (free shipping). Both passed. The bug lived in the one place nobody looked: the exact edge, €50.00. The developer had written “more than 50” instead of “50 or more”.
This is the most common kind of bug in the world, and there’s a technique built to catch it: boundary value analysisBoundary value analysisTesting values at and just around the edges of valid ranges, where bugs love to hide.Open in glossary → (BVA).
Why bugs cluster at the edges
In Equivalence Partitioning you learned to split values into groups that behave the same, like ages 17-and-under, 18–60 and 61-and-over in a fitness app’s sign-up form. A boundary is the edge of one of those groups: the smallest or largest value in a partition.
Developers turn requirements into comparisons like “greater than” or “less than or equal to”. Picking the wrong one, or a number that’s one too high or too low, is an off-by-one errorOff-by-one errorA bug where a count or boundary is wrong by exactly one, like counting days instead of nights.Open in glossary →. The code works for almost every value and fails only at the edge:
| Requirement | Bug in the code | Only caught by |
|---|---|---|
| Age 18 or older | age > 18 (should be >=) | 18 |
| Free shipping from €50 | total > 50 (should be >=) | €50.00 |
| Password max 64 chars | len <= 63 (should be 64) | 64 chars |
| Up to 10 items | qty < 10 (should be <=) | 10 items |
In every row, a value from the middle of the partition (35, €80, 20 characters, 5 items) passes perfectly. Only a value at the edge reveals the problem. That’s the whole case for BVA: test exactly where the behavior changes.
The quick version
2-value and 3-value BVA
For the age rule 18–60 there are two boundaries: 18 (the smallest valid age) and 60 (the largest).
2-value BVA tests each boundary plus its closest neighbor on the other side:
2-value BVA · age 18–60
≤ 17
Invalid
18 – 60
Valid
≥ 61
Invalid
3-value BVA tests each boundary plus its closest neighbors on both sides:
3-value BVA · age 18–60
≤ 17
Invalid
18 – 60
Valid
≥ 61
Invalid
Most everyday testing uses 2-value BVA. Teams switch to 3-value for risky rules: money, security, legal age limits.
Boundaries are everywhere
- Lengths: password 8–64 characters → 7, 8, 64, 65.
- Dates: first and last day of a month, 29 February, 31 December, yesterday / today / tomorrow.
- Money: €0.00, €0.01, and the maximum (a €1,000 transfer limit → €1,000.00 and €1,000.01).
- Lists: 0 items, 1 item, the maximum, one more than the maximum.
- Outputs: free shipping at €50.00, so test €49.99 and €50.00.
BVA and EP work together
EP picks one value from the middle of each partition (35); BVA tests the edges (17, 18, 60, 61). EP also covers partitions that have no edges at all, like an empty field or “abc”. Use both, every time.
Finding the boundaries step by step
- Start with your partitions. BVA builds on EP. For the age field: 17 or less, 18–60, 61 or more.
- Find the step size. What is the smallest possible change? 1 for whole years, 1 for characters, €0.01 for euros, 1 day for dates.
- Find each boundary. The smallest and largest value of each ordered partition: 18 and 60.
- Add the neighbors. One step outside each boundary (17, 61). For 3-value BVA, also one step inside (19, 59).
- Write the expected result for each value. 17 is rejected, 18 is accepted, and so on. A boundary test without an exact expected result is just a guess.
2-value BVA
For each boundary, test the boundary value itself and the closest value on the other side of the boundary (in the neighboring partition).
2-value BVA · age 18–60
≤ 17
Invalid
18 – 60
Valid
≥ 61
Invalid
| Value | Why | Expected |
|---|---|---|
| 17 | Last invalid value below the range | Rejected |
| 18 | Lower boundary, first valid value | Accepted |
| 60 | Upper boundary, last valid value | Accepted |
| 61 | First invalid value above the range | Rejected |
This catches the classic mistakes: > instead of >= at the lower edge (18 is wrongly rejected), age <= 61 instead of age <= 60 (61 is wrongly accepted), or age < 60 instead of age <= 60 (60 is wrongly rejected).
3-value BVA
For each boundary, test the boundary value and the closest value on both sides.
3-value BVA · age 18–60
≤ 17
Invalid
18 – 60
Valid
≥ 61
Invalid
The extra values (19 and 59) look redundant, but they catch bugs that 2-value BVA misses. Imagine a developer wrote age == 18 (exactly 18) instead of age >= 18 for the lower check:
| Value | Correct result | Buggy age == 18 | Caught? |
|---|---|---|---|
| 17 | Rejected | Rejected | No |
| 18 | Accepted | Accepted | No |
| 19 | Accepted | Rejected | Yes |
2-value BVA (17 and 18) passes and the bug ships. Only 19, the inside neighbor, exposes it.
| Method | Values for 18–60 | Tests | Best for |
|---|---|---|---|
| 2-value | 17, 18, 60, 61 | 4 | Everyday features |
| 3-value | 17, 18, 19, 59, 60, 61 | 6 | Money, security, legal limits |
Boundaries are everywhere
Lengths
A banking app requires passwords of 8 to 64 characters. The step is one character.
Password length (8–64 characters)
0 – 7
Too short
8 – 64
Accepted
≥ 65
Too long
Practical tips:
- Count precisely. Prepare test strings of exact lengths in a notes file (for example
Abcdef1!is 8 characters). A character counter tool helps for 64. - Watch for silent truncation. If the field stops accepting input after 64 characters, typing 65 just gives you 64. That’s often fine, but check that a pasted 65-character password isn’t silently cut to 64 and saved, so the user can never log in with what they typed. See truncationTruncationText that gets cut off because it doesn't fit its space.Open in glossary →.
- Password managers generate long passwords. A real-world max-length bug (a limit of 63 instead of 64) hits exactly those careful users. More in Login and Sign-up.
Dates
Dates have more boundaries than any other data type. The step is usually one day (sometimes one minute).
| Boundary | Test values | Typical bug |
|---|---|---|
| Month end | 31 Jan → 1 Feb, 30 Apr | “31 April” accepted, or a 30-day month gets 31 |
| Leap day | 29 Feb 2028 (valid), 29 Feb 2027 (invalid) | Leap year rule wrong, or a crash on 29 Feb |
| Year end | 31 Dec → 1 Jan | Year doesn’t roll over in a booking |
| “Not in the past” | yesterday, today, tomorrow | Today wrongly blocked, or yesterday allowed |
| Age from birth date | turned 18 today vs. turns 18 tomorrow | Off by a day around the birthday |
Midnight is a boundary too, and time zonesTime zoneThe local time of a region. Bugs appear when apps mix up the user's time zone with the server's.Open in glossary → move it: “today” for a hotel in Tokyo may still be “yesterday” for a user in New York. Daylight saving changes create days with 23 or 25 hours (see Daylight saving time (DST)Daylight saving time (DST)Moving clocks forward in spring and back in autumn, creating a skipped hour and a repeated hour.Open in glossary →). The Date Picker page has lots of examples.
Money
The step for euros, dollars and pounds is one cent (0.01). Some currencies, like the Japanese yen, have no cents in everyday use, so the step is 1.
A banking app allows transfers from €0.01 to €1,000.00 per day:
Transfer amount (€0.01–€1,000.00)
≤ €0.00
Rejected
€0.01 – 1,000
Sent
≥ €1,000.01
Over limit
Also try amounts with more decimals than allowed (€10.999), very large numbers (€99,999,999), and think about rounding: does €0.005 become €0.01 or €0.00?
Lists and counts
Anything you can count has boundaries: items in a cart, photos in a review, results on a page, seats on a flight.
| Count | Why it matters |
|---|---|
| 0 | The empty stateEmpty stateThe screen a user sees when there is no content yet, like an empty cart or no search results.Open in glossary →: empty cart, no search results. Checkout must be disabled, a friendly message shown. |
| 1 | Singular text (“1 item”, not “1 items”), lists that break with only one row. |
| Max | A review allows 5 photos: the 5th must upload. |
| Max + 1 | The 6th photo must be blocked with a clear message, not crash or silently vanish. |
paginationPaginationSplitting a long list into pages that load one at a time.Open in glossary → is a great place to look: with 20 results per page, test 20 results (one page) and 21 results (a second page with a single item).
Outputs
Just like EP, BVA works on outputs. Find the input values that put you right at the edge of a different result.
Shipping cost (output boundaries)
under €20
€4.99
€20 – 49.99
€2.99
≥ €50
Free
Remember that outputs depend on the final number: a €55 cart with a €5 coupon is exactly €50.00. Does it still get free shipping? See Shopping Cart and Checkout.
Classic boundary bugs
| # | Bug | What you see | Typical severity |
|---|---|---|---|
| 1 | > instead of >= | An 18-year-old can’t sign up | High |
| 2 | Free shipping at “more than” €50 | €50.00 cart pays €4.99 | Medium |
| 3 | Max length one too short | 64-char password rejected | Medium |
| 4 | Leap day not handled | Booking for 29 Feb crashes | High |
| 5 | Limit check on the wrong side | €1,000.01 transfer goes through | Critical |
| 6 | Count off by one | A 6th photo uploads although the limit is 5 | Low–Medium |
How BVA complements EP
| Equivalence partitioning | Boundary value analysis | |
|---|---|---|
| Picks | One value from inside each partition | Values at and next to each edge |
| Age 18–60 | 12, 35, 72 | 17, 18, 60, 61 |
| Catches | Whole partitions handled wrongly | Off-by-one and wrong comparisons |
| Also covers | Empty, “abc”, 25.5 (no edges) | Only ordered values |
Together, a strong test set for the age field is: 35 (valid, EP), 17, 18, 60, 61 (BVA), plus empty, abc, 25.5 (EP partitions without edges). That’s 8 tests. You could drop 12 and 72, since 17 and 61 already represent those partitions.
Writing test cases from BVA
- One boundary value per test when it’s invalid, and keep every other field valid, so you know which value caused the error (the same rule as in EP).
- Put the exact value in the title or data. “Sign-up accepts age 18 (lower boundary)” is far clearer than “Test age boundary”.
- Write an exact expected result. Not “works”, but “Account is created and the Goals screen opens”.
- Valid boundaries can be combined when the fields are independent: 1 night, 1 guest and check-in today in one booking. If it fails, split it up.
- Link back to the requirement, so anyone can see why 64 and 65 matter.
You’ll find complete examples below, and more on the format in How to Write Test Cases. When a boundary test fails, report the exact value and what you expected; the bug report almost writes itself (see How to Write Bug Reports).
See also: Error Guessing and Checklists, which picks up where the boundaries stop: zero, negatives, other number formats and time zones.
Practice: pick the boundary values
Choose a rule and a mode, then tap the values you would test. After checking, the underline shows which values are valid (green) and invalid (red).
🎯 Boundary game: pick the edge values
Tap the values you would test. Then check your picks.
Fitness app · sign-up
Age must be from 18 to 60 (inclusive).
2-value BVA: for each boundary, test the boundary value and its closest neighbor on the other side. Values move in steps of 1.
Around 18
Around 60
Find the off-by-one bugs
Three of these six rules were implemented with an off-by-one bug; the other three are correct. You can’t see the code, only the results. Test each rule with boundary values, decide whether it’s buggy, then check your verdicts.
🐞 Buggy implementation mode
Some of these six rules have an off-by-one bug. Use boundary values to find out which, then give your verdict.
Sign-up age
Ages 18 to 60 can sign up.
Cart quantity
You can buy 1 to 10 of one item.
Free shipping
Shipping is free from €50.00.
Password length
Passwords must be 8 to 64 characters.
Hotel stay
A booking is 1 to 30 nights.
Promo code length
Codes are 6 to 10 characters.
0/6 verdicts given
Exercise: a hotel booking form
Time to combine both techniques. Derive EP partitions and BVA values for this small travel app spec, type them in, and compare with the model answer.
✍️ Exercise: hotel booking form
Write the EP and BVA values you would test for each field, then compare with the model answer.
Spec · Travel app · "Book a room"
- Nights: 1 to 30 whole nights.
- Guests: 1 to 4 guests per room.
- Check-in date: not in the past; at most 365 days ahead.
- All three fields are required.
Separate values with commas. Type empty for a blank field and any word (like abc) for non-numeric input.
Example test cases
TC-BVA-01Sign-up accepts age 18 (lower boundary)edgehigh
Preconditions
- Fitness app is on the Create account screen
Steps
- Enter a valid email and password
- Enter age 18
- Tap Continue
Test data
age: 18
Expected result
No error is shown and the Choose your goals screen opens.
TC-BVA-02Sign-up rejects age 17 (just below the lower boundary)negativehigh
Preconditions
- Fitness app is on the Create account screen
Steps
- Enter a valid email and password
- Enter age 17
- Tap Continue
Test data
age: 17
Expected result
'You must be at least 18 to sign up' appears under Age and the account is not created.
TC-BVA-03Order of exactly €50.00 gets free shippingedgehigh
Preconditions
- Shop cart is empty
- Free shipping threshold is €50.00
Steps
- Add products worth exactly €50.00 to the cart
- Open the cart
Test data
cart total: €50.00
Expected result
Shipping shows 'Free' and the order total is €50.00.
TC-BVA-04Order of €49.99 pays standard shippingedgemedium
Preconditions
- Shop cart is empty
- Free shipping threshold is €50.00
Steps
- Add products worth €49.99 to the cart
- Open the cart
Test data
cart total: €49.99
Expected result
Shipping shows €2.99 and the message 'Add €0.01 more for free shipping' is displayed.
TC-BVA-05Password of exactly 64 characters is accepted (upper boundary)edgemedium
Preconditions
- Banking app is on the Set new password screen
Steps
- Paste a 64-character password into New password and Confirm password
- Tap Save
- Log out and log in with the same password
Test data
password: 64 characters (letters, digits and symbols)
Expected result
The password is saved, and logging in with all 64 characters works.
TC-BVA-06Password of 65 characters is rejected (just above the upper boundary)negativemedium
Preconditions
- Banking app is on the Set new password screen
Steps
- Paste a 65-character password into New password
- Tap Save
Test data
password: 65 characters
Expected result
'Password must be at most 64 characters' is shown and nothing is saved. If the field cuts pasted text to 64 characters instead, the user is clearly told; a silently shortened password is a bug.
Tip: click a test case to expand it.
Boundary value analysis checklist
0 of 10 checked
Check your understanding
Quick quiz
0/6 answered · 0 correct
1.Age must be 18 to 60. What is the 2-value BVA set?
2.Which extra values does 3-value BVA add for the same 18–60 rule?
3.Free shipping applies to orders of €50.00 or more. Which pair of tests is most likely to find a '>' vs '>=' bug?
4.A review lets you attach up to 5 photos. Which counts should you test with BVA?
5.Why doesn't BVA apply to a list of payment methods (Card, PayPal, Pay on delivery)?
6.A hotel booking says check-in can't be in the past. Which dates are the boundary tests?
Key takeaways
- Bugs cluster at edges because developers easily mix up
>and>=, or type a limit one too high or too low (an off-by-one error). - A boundary is the smallest or largest value of an ordered partition. Find the step size first (1, €0.01, one day).
- 2-value BVA: the boundary and its neighbor outside (17, 18 / 60, 61). 3-value BVA adds the neighbor inside (17, 18, 19 / 59, 60, 61).
- Boundaries hide in lengths, dates, money, counts and outputs, and in technical limits nobody wrote down.
- BVA complements Equivalence Partitioning: EP covers the middle and edge-less partitions; BVA covers the edges.
- Write each boundary test with the exact value and an exact expected result.
Finished this page?Nice work, this page is complete!
Mark it as done to track your progress. It's saved in this browser, no account needed.
Its review cards are now in Bites ⚡