Test design techniques
Test smart — cover more with fewer, well-chosen test cases.
Topic 7 — Test design techniques
Goal: Test smart — cover more with fewer, well-chosen test cases.
Lesson 7.1 — The promo-code field that could break a thousand ways
Tom drops a one-line ticket on Nadia: test the new promo-code field at checkout. It takes a code of 6 to 10 characters. She opens FreshCart, types SAVE5 into the box, and stops.
Six to ten characters. Letters, numbers, who knows what else. If she tried to test every possible code, she'd be at her desk until retirement. Back at the pharmacy she never checked every pill in a bottle either — she checked the count, the label, and the few that mattered. Same instinct, new field.
This is the whole problem Topic 5 left open: exhaustive testing is impossible, so testing randomly until you get bored is the only alternative — unless you have a method.
Test design techniques are proven methods for choosing the right handful of tests: maximum coverage from minimum effort. They're black-box techniques — you design them from the requirement alone, no code or programming needed. You'll learn three that do most of the heavy lifting, plus the unscripted craft that finds what they miss.
Good testing means choosing the few tests most likely to find a bug, not running more of them. Marcus puts it plainly in her second week: "Anyone can click around for an hour. Your job is to click the right twenty times."
Lesson 7.2 — Equivalence partitioning: one test stands for thousands
Nadia goes back to that promo field. "Six to ten characters" — so a 3-character code should be rejected, a 7-character code accepted, a 14-character code rejected. She starts writing a test for length 6, then 7, then 8, then 9, then 10, and Marcus leans over.
"Do you think the code treats a 7-character entry differently from an 8-character one?"
Probably not. The system handles every valid-length code the same way. So testing all of them tells her nothing new after the first.
That's equivalence partitioning: group the inputs into classes the system should treat identically, then test just one example from each class. The promo field has three classes — too short (say, 3 characters), valid length (say, 7), and too long (say, 14). One representative from each, and three tidy tests stand in for thousands.
Think about FreshCart's age gate on alcohol. The law says you must be 21+ to buy beer, so that's the rule the field enforces: a single-sided cutoff with two classes — too young (e.g. 16) and old enough (e.g. 30). One value per class, two tests, every age covered. You don't test 21, 22, 23, all the way up; a single valid value represents every legal age.
The skill is spotting the classes correctly. Miss a class and you've left a gap; one is plenty per class you find.
Lesson 7.3 — Boundary value analysis: bugs live at the edges
Nadia is proud of her two age tests — 16 and 30 — until Priya, the developer, says something offhand at standup: "Honestly, the bugs I write are almost always off-by-one. I type > when I meant >=."
That sentence reorganizes how Nadia tests.
If Priya wrote age > 21 instead of age >= 21, then a 21-year-old gets blocked by mistake — and Nadia's test value of 30 sails right past the bug. The mistake hides exactly at the edge of the rule, and her comfortable-middle example never touches it.
Boundary value analysis (BVA) targets those edges on purpose. Bugs cluster at boundaries because that's where the off-by-one errors live, so you test right at and around each one. For the 21+ alcohol gate: test 20, 21, 22 — the last age that should be blocked, the cutoff itself, and the first age safely over it. A two-sided range has two edges to probe. The promo-length field below is one of those, and you hit both ends the same way.
A few things to hold onto:
- BVA only applies to ordered or numeric ranges — ages, prices, quantities, dates, character counts. It makes no sense for a list like "Visa / Mastercard / Amex."
- It sits on top of equivalence partitioning, not instead of it. First you find the classes; then you probe the edges between them.
- The boundary itself plus one step either side is usually enough.
Nadia rewrites her promo-length tests around the edges: 5 (just too short), 6 (minimum valid), 10 (maximum valid), 11 (just too long). She runs 6, it passes. She runs 5, and the field accepts it. There's the bug — the developer used "5 or more" instead of "6 or more." Her middle-of-the-road tests would never have found it.
Lesson 7.4 — Decision tables: when the rules combine
Promo codes were one input. FreshCart's free-delivery rule is messier, and Tom's spec spells it out: delivery is free when the order is $30 or more AND the customer is a member. Anything else, the customer pays the $4 fee.
Nadia's first instinct is to test "big order, gets free delivery." Marcus stops her. "What about a member with a $12 order? What about a $50 order from someone who isn't a member?" The outcome depends on a combination of conditions, and combinations are where rules quietly break.
When an outcome hangs on several conditions at once, you build a decision table: list the conditions, lay out every meaningful combination, and write down the expected result for each. The table forces you to confront the cases you'd skip on instinct.
Free delivery needs (order ≥ $30) AND (is a member):
| Order ≥ $30? | Member? | Expected result |
|---|---|---|
| Yes | Yes | Free delivery |
| Yes | No | $4 fee |
| No | Yes | $4 fee |
| No | No | $4 fee |
Four rows, four tests, every combination covered. Row 3 — member, but under $30 — is the one almost everybody forgets, and it's a classic spot for a developer to accidentally hand out free delivery to any member at all. The table makes the gap impossible to miss.
Two conditions give four rows. Add a third (say, a first-order coupon) and you get eight. Decision tables shine for exactly this kind of business logic, where the requirement reads "free when X and Y but not Z" and your job is to make sure each rule actually holds.
Lesson 7.5 — Exploratory testing: what the script never imagined
Nadia's scripted cases all pass. Green across the board. She's about to mark the checkout done when Dev, the automation engineer, wanders by with a grin: "Cases all pass? Cool. Now go break it."
Scripted tests only check what someone thought of in advance. Real users don't read your test plan.
Exploratory testing is investigating the product without a fixed script — designing and running tests on the fly, led by knowledge, curiosity, and "what happens if I…?" Nadia starts poking at checkout the way an unpredictable customer would:
- She hits the back button mid-payment, then forward again. The order total double-counts the promo discount.
- She types emojis into the cardholder-name field. The page hangs.
- She drops her wi-fi halfway through tapping "Pay," then reconnects. The app shows "payment failed" but the bank charged the card.
- She applies a promo code, removes the item it discounted, and the discount sticks around on an empty-ish cart.
Four real bugs, none of them on any script, all found in twenty minutes of curious prodding. This is where a sharp QA mind earns its keep — chasing the weird, real-world edges that rigid cases can't anticipate.
It is not random clicking, though. Exploratory testing is purposeful: Nadia has a hunch ("the back button probably confuses the total"), she investigates it, and she writes down what she finds. The freedom is in the path, not the intent.
There's a reason she can't just lean on her old scripts forever. The ISTQB calls it the pesticide paradox: run the same tests over and over and they eventually stop finding new defects, the way pests grow resistant to a spray they've survived before. Test suites have to be reviewed, updated, and topped up with fresh exploratory sessions, or they slowly go blind to new bugs.
Scripted testing proves the known requirements still work. Exploratory testing discovers the problems nobody wrote a requirement for.
Worked example — Designing the FreshCart checkout tests in one afternoon
Tom hands Nadia the full checkout spec: quantity per item is 1–10; free delivery when order ≥ $30 AND member; promo codes are 6–10 characters. She has an afternoon. Watch her use all four tools instead of brute force.
She starts with equivalence partitioning on the quantity field — three classes: too low (0), valid (5), too high (11). Three tests, not eleven.
Then boundary value analysis on that same field, because it's numeric: 0, 1, 2 at the bottom edge and 9, 10, 11 at the top. Running 0, the cart lets her add zero of an item and pay $0.00 — bug filed, and a comfortable quantity of 5 never would've found it.
For the free-delivery rule she builds a decision table of the two conditions, four rows. Testing the member, under $30 row, delivery comes back free when it should be $4 — a real money bug, and the row she'd have skipped on gut feel.
With the scripted cases done and passing, she spends the last hour on exploratory testing: back button mid-payment, emojis in the name field, wi-fi dropped at "Pay." Two more bugs surface.
By five o'clock she's run roughly twenty deliberate tests and filed five bugs. A teammate who clicked around randomly for the same afternoon found one. Same time, same app — the difference was technique.
Key terms
- Test design technique — a proven method for choosing high-value tests; black-box, needs no code.
- Equivalence partitioning — group inputs into classes treated the same; test one example per class.
- Equivalence class (partition) — one such group of inputs (e.g. "valid ages," "too young").
- Boundary value analysis (BVA) — test at and around the edges of a numeric range, where off-by-one bugs cluster.
- Decision table — a grid of condition combinations and their expected results, for combined-rule logic.
- Exploratory testing — purposeful, unscripted investigation; design and run tests on the fly.
- Scripted testing — running predefined test cases for repeatable coverage of known requirements.
- Pesticide paradox — the ISTQB principle that repeating the same tests stops finding new defects.
Try this
Take FreshCart's tip field at checkout: it accepts a tip from $0 to $50. On paper, design the tests. First write your equivalence classes (below range, valid, above range) with one value each. Then add the boundary values at both edges. Finally, list three exploratory "what happens if I…?" questions you'd try on it (think: pasting a negative number, typing letters, entering 49.999). You should end up with a small, sharp set — that's the same move Nadia makes before she touches the app.
Common pitfalls
- Testing many values from the same class. Running quantities 3, 4, 5, 6, 7 feels thorough but they're all one equivalence class — you learn nothing after the first. Spend that effort on the boundaries instead.
- Skipping the boundaries. Comfortable middle values (age 30, quantity 5) sail past the off-by-one bugs that live at 21 and 1. The edges are the whole point of BVA.
- Forgetting a decision-table row. Testing only the "everything true" case and missing the member-but-under-$30 combination is how free delivery quietly leaks. Lay out every row.
- Treating exploratory testing as aimless clicking. Wandering with no hunch and no notes is just clicking, not exploratory testing. Investigate a specific question, then write down what you find.
Key takeaways
- Exhaustive testing is impossible, so use techniques to pick the smartest few tests, not brute force or random clicking.
- Equivalence partitioning: group inputs into classes treated the same; test one example per class.
- Boundary value analysis: test at and around the edges of numeric ranges, on top of partitioning, because off-by-one bugs cluster there.
- Decision tables: when an outcome depends on a combination of conditions, lay out every rule and test each.
- Exploratory testing finds the weird real-world bugs scripts miss; combine scripted and exploratory, and refresh your tests to beat the pesticide paradox.
Preparing your quiz…