Test design techniques (so you test smart, not endless)
The core black-box techniques (equivalence partitioning, boundary value analysis, decision tables, and state transition), with worked examples so you pick a few powerful tests instead of drowning in thousands.
Here's a problem. A simple age field accepts numbers from 0 to 120. How many values could you type? Whole numbers, decimals, negatives, gigantic numbers, letters, blanks, emoji. The combinations are effectively endless. You will never finish. So the real skill of a tester isn't running tests: it's choosing which handful of tests is worth running out of the infinite pile.
That's what test design techniques give you: small, proven recipes for picking representative cases that catch the most bugs for the least effort. These are all black-box techniques, meaning you design them from how the software is supposed to behave, without needing to see the code inside.
Equivalence partitioning: group, then test one of each
The idea is simple: if a bunch of inputs all should be treated the same way, you only need to test one of them. Sort your inputs into groups ("partitions") where everything in a group behaves alike, then pick one value from each group as your representative.
Take that age field accepting 0 to 120. The inputs fall into three partitions: too low (anything below 0), valid (0 through 120), and too high (above 120). Instead of testing hundreds of numbers, you test one from each group: maybe -5, 40, and 200. If the app handles those three correctly, it almost certainly handles every other value in the same group too.
Equivalence partitioning slashes your test count without slashing your coverage. The trick is making sure your partitions are honest: that everything inside really does behave the same. If you suspect a group secretly has sub-groups, split it.
Boundary value analysis: bugs love the edges
Here's a truth you can almost set your watch by: bugs cluster at the edges of a range, not in the comfortable middle. A developer writes if (age > 18) when they meant >= 18, and suddenly an 18-year-old is wrongly rejected. The middle of the range works fine; only the boundary breaks. So you test the boundaries deliberately.
The classic example: a form accepts ages from 18 to 60 inclusive. Boundary value analysis says test the values right on and right around each edge: the boundary itself, one below, and one above:
| Value | Where it sits | Expected result |
|---|---|---|
| 17 | Just below the lower edge | Rejected (too young) |
| 18 | On the lower edge | Accepted |
| 19 | Just inside the lower edge | Accepted |
| 59 | Just inside the upper edge | Accepted |
| 60 | On the upper edge | Accepted |
| 61 | Just above the upper edge | Rejected (too old) |
Six well-chosen values, and you've cornered nearly every off-by-one mistake a developer could make on this field. Pair this with equivalence partitioning and you get a tiny, deadly-effective set: a representative from each group, plus the edges between them.
Decision tables: when rules combine
Some behaviour depends on several conditions at once, and the rules tangle together. "Free shipping if the order is over $50 or the customer is a member." Now you have two conditions and four combinations. A decision table lays every combination out in a grid so you can't accidentally forget one.
| Order over $50? | Member? | Free shipping? |
|---|---|---|
| No | No | No, charge shipping |
| No | Yes | Yes |
| Yes | No | Yes |
| Yes | Yes | Yes |
Each row becomes one test case. The table makes gaps obvious: if you'd only thought to test "big order" and "member", you'd have missed the small-order-non-member row: the one that's supposed to charge shipping, and the one most likely to be wrong.
State transition: when order matters
Sometimes the software behaves differently depending on what state it's in, and the same action does different things at different times. Think of an ATM card: after three wrong PINs it gets blocked, and a fourth attempt (even with the right PIN) does nothing. The action ("enter PIN") isn't right or wrong on its own; it depends on the history.
Active
0 wrong tries
1 wrong
warning shown
2 wrong
last chance
Blocked
card locked
State transition testing maps these states and the moves between them, then checks both the moves that should be allowed (a wrong PIN nudges you toward Blocked) and the ones that shouldn't (a correct PIN while Blocked must still refuse). The bugs hide in the transitions nobody drew on the diagram.
You can't test everything: the combinations are infinite and your time is not. These techniques are how professionals turn an impossible pile into a short, smart list: group the similar inputs, hammer the edges, chart the rule combinations, and follow the states. Fewer tests, more bugs caught.
- You can never test every input, so the craft is choosing a small set of representative cases.
- Equivalence partitioning groups inputs that behave alike and tests one from each group.
- Boundary value analysis tests the edges of a range (on, just below, just above), where off-by-one bugs live.
- Decision tables lay out every combination of conditions so no rule slips through.
- State transition testing checks how the software moves between states, including the moves that should be blocked.