Test design: equivalence partitioning and boundary values
The previous lesson said "cover each class of behaviour with a representative case" and "bugs cluster at boundaries". This lesson gives you the two techniques that make those precise — equivalence partitioning and boundary value analysis. They are the most useful test-design tools in a QA's kit: they let you reduce an infinite set of possible inputs to a small, well-chosen set that covers the real risk, and they tell you exactly which values to try. Grounded, again, in the top-up amount field.
The problem: infinite inputs, finite time
The top-up amount field can take, in principle, infinitely many values — every number, plus letters, symbols, empty. You cannot test them all, and testing "a few random ones" misses the values that matter. The two techniques solve this: equivalence partitioning reduces the infinite set to a handful of classes, and boundary value analysis picks the specific values within and between them where bugs live. Together they turn "I tried some amounts" into "I covered every class of input and every boundary, with a defensible, minimal set".
Equivalence partitioning: group inputs that behave the same
Equivalence partitioning divides the input space into classes (partitions) where every value in a class should be treated the same way by the software — so testing one value from each class is representative of the whole class. For the top-up amount (say valid range is ₹1 to ₹10,000):
| Partition | Example value | Expected |
|---|---|---|
| Below minimum (≤ ₹0) | -50, 0 | rejected |
| Valid range (₹1 to ₹10,000) | ₹100 | accepted |
| Above maximum (> ₹10,000) | ₹15,000 | rejected |
| Non-numeric | "abc", "💸" | rejected |
| Empty | "" | rejected |
The logic: if ₹100 works, ₹250 and ₹4,000 almost certainly work the same way (same partition) — so you do not need to test all three; one representative per partition covers it. This is why you do not test "a hundred valid amounts" — they are one equivalence class, and one value tests the class. You test one from each partition: one valid, one below, one above, one non-numeric, one empty. Five test cases cover the infinite input space by class. Partition both valid classes (the accepted ranges) and invalid classes (each distinct way it should be rejected) — a common mistake is partitioning only the valid inputs and under-testing the ways it should say no.
Boundary value analysis: test the edges of each partition
Equivalence partitioning tells you the classes; boundary value analysis tells you that bugs cluster
at the edges of those classes, so you test the values right at and around each boundary. Why the edges?
Because boundaries are where developers write comparisons (if amount < 1, if amount > 10000), and those
comparisons are where off-by-one errors live — < versus <=, > versus >=. The classic bug is the
maximum being one off: the field accepts ₹10,001 when it should stop at ₹10,000, or rejects ₹10,000
itself.
So for each boundary, test the boundary and one on each side:
- Around the minimum (₹1): test ₹0 (just below — should reject), ₹1 (the boundary — should accept), ₹2 (just above — should accept).
- Around the maximum (₹10,000): test ₹9,999 (just below — accept), ₹10,000 (the boundary — accept), ₹10,001 (just above — reject).
These six values catch the off-by-one bugs that a "random valid amount" never would. Boundary analysis is
the highest-value test-design technique precisely because it targets where the code makes decisions and
where developers most often get the < vs <= wrong. Whenever you see a field with a range, a limit, a
length, or a count, your instinct should be: test the boundary and one either side.
Combining them, and other boundaries
The two work together: partition to find the classes, then boundary-analyse the edges of each. From the top-up field, that gives a tight, defensible set — one representative per partition (valid, non-numeric, empty) plus the boundary triples at the min and max — maybe ten values that cover the infinite input space and all the likely bug locations.
Boundaries are everywhere once you look, not just numeric ranges:
- Length — a name field of max 60 characters: test 59, 60, 61 characters, and empty.
- Count — "up to 5 items": test 0, 4, 5, 6 items.
- Dates — the first and last valid date; the day a promotion starts and ends.
- Time / expiry — a session that lasts 30 minutes: test at 29, 30, 31 minutes.
- Zero, empty, and null — always worth a test; they are boundaries of "nothing", and code often mishandles them.
Any limit in a requirement ("minimum", "maximum", "up to", "at least", "expires after") is a boundary to attack with the-boundary-and-one-either-side.
Why these techniques matter
Beyond finding bugs, these techniques give you two things a QA needs. First, coverage you can defend — you can say "I tested one value per equivalence class and the boundary of each, here is the set", which is a rational, explainable strategy, not "I tried some". Second, efficiency — you get strong coverage with a small number of tests, which matters because your time is limited (the risk-based lesson). A tester who knows these techniques covers the amount field thoroughly in ten well-chosen cases; one who does not either misses the boundary bugs or wastes time testing a hundred equivalent valid amounts. This is the difference between test design as a skill and test design as guessing — and it is exactly what an interviewer for a QA role will probe.
Check your work
The problem. Infinite inputs, finite time — you cannot test all values, and random ones miss what matters.
Equivalence partitioning. Divide inputs into classes treated the same; test one representative per class — valid range(s) and each distinct invalid class (below, above, non-numeric, empty). One valid amount tests all valid amounts; do not under-test the invalid classes.
Boundary value analysis. Bugs cluster at the edges of partitions (where code compares — < vs <=);
test the boundary and one on each side (0/1/2 at the min, 9,999/10,000/10,001 at the max) to catch
off-by-one errors.
Combine them. Partition to find classes, boundary-analyse each edge — a tight, defensible ~10-value set covering the infinite space. Boundaries are everywhere: length, count, dates, time/expiry, zero/empty/null.
Why it matters. Defensible coverage ("one per class + each boundary") and efficiency (strong coverage, few tests) — test design as a skill, not guessing.
Practice
- Partition the top-up amount field into all its classes (valid and each invalid kind) and pick one representative value per class.
- For the min (₹1) and max (₹10,000), write the boundary triples (below/at/above) and state the expected result of each — spot where an off-by-one would show.
- Do the same for a name field of max 60 characters: partitions and boundary values.
- Take a requirement with "up to 5" of something and write the boundary values (0/4/5/6).
- Find a real limit in an app you use (a max length, a max amount, an expiry) and test the boundary and one either side; note whether it is off by one.
- Justify, to an imagined interviewer, why testing 10 well-chosen values beats testing 100 random valid ones.
Official documentation
- ISTQB — Foundation syllabus (black-box techniques) — Equivalence partitioning and boundary value analysis, formally.
- ISTQB — Glossary — Precise definitions of the techniques.
- Ministry of Testing — Test design — Practitioner articles applying the techniques.
Next: test plans and coverage.
Stuck on this lesson?
Being stuck is part of it — but being stuck alone for three days is not. Our internship programme pairs this curriculum with code review and one-to-one help from working developers, and it is free.
About the internship