AI-Led Quality EngineeringBeginnerTest design
Test Design Techniques: EP, Boundary Values and Decision Tables
Learn equivalence partitioning, boundary value analysis, decision tables, state transitions and pairwise testing, with worked examples and how to write a good test case.
What is test design?
Test analysis and design exist to answer one question: given a requirement, which few tests, out of the huge number possible, are most likely to find a defect? The techniques below are how professionals choose them on purpose, not by hunch. They follow the test design techniques of the ISTQB Foundation Level syllabus (v4.0.1, section 4) and ISO/IEC/IEEE 29119-4. The worked examples use an insurance quoting and policy system, the kind of application our learners test.
What you will be able to do after this guide
- Explain the test process activities (analysis, design, implementation, execution) and what each produces.
- Apply equivalence partitioning, boundary value analysis, decision tables and state transition testing to a real business rule.
- Describe use case testing, statement and branch coverage, and when pairwise testing helps.
- Use experience-based techniques (error guessing, exploratory, checklist-based) alongside the formal ones.
- Write a clear, traceable test case with a specific expected result.
- Use AI to draft test cases and review them like a professional.
1. From requirement to test: the activities
Testing is a process, and the design techniques sit in the middle of it.
| Activity | Question it answers | Output |
|---|---|---|
| Test analysis | What should we test? | Test conditions: things to check, taken from requirements and risks ("driver under 16 is rejected") |
| Test design | How should we test it? | Test cases: inputs, steps and expected results, chosen by a technique |
| Test implementation | What do we need to run them? | Ordered test procedures or scripts, test data, environment ready |
| Test execution | Does it behave as expected? | Results, defects, evidence |
- Test analysisWhat should we test? Output: test conditions
- Test designHow should we test it? Output: test cases
- Test implementationWhat do we need to run them? Output: procedures, data, environment
- Test executionDoes it behave as expected? Output: results and defects
Analysis comes first: a test condition such as "age eligibility" is broad; the design technique turns it into specific test cases. A test case is a set of preconditions, inputs, actions and an expected result, derived from a test basis such as a requirement.
2. The three families of technique
| Family | Basis for choosing tests | Examples |
|---|---|---|
| Black-box (specification-based) | What the system should do, taken from requirements, not code | Equivalence partitioning, boundary values, decision tables, state transitions, use cases |
| White-box (structure-based) | The structure of the code | Statement and branch coverage |
| Experience-based | The tester's knowledge, intuition and past defects | Error guessing, exploratory, checklist-based |
They are complementary. Black-box finds missing and wrong behaviour; white-box shows what code has not been exercised; experience-based finds what nobody wrote down. A strong approach combines them.
3. Equivalence partitioning (EP)
The idea: divide the possible inputs into groups (partitions) that the system should treat the same way. If one value in a group works, the others in the group very probably work too, so you test one representative per partition instead of every value.
Suppose (illustrative) the insurance system's rating rule for driver age says: under 16 is rejected, 16 to 24 is rated as a young driver, 25 to 99 as standard, and 100 or more is invalid.
| Partition | Values | Valid? | Representative test |
|---|---|---|---|
| Below minimum | 0 to 15 | Invalid (rejected) | 10 |
| Young driver | 16 to 24 | Valid | 20 |
| Standard | 25 to 99 | Valid | 50 |
| Above maximum | 100 and over | Invalid | 120 |
| Not a number | letters, symbols | Invalid | "abc" |
| Empty | no value | Invalid | (blank) |
Five or six tests now stand for thousands of possible inputs. Always include the invalid partitions: that is where error handling is checked. EP also applies to non-numeric inputs (a product type of auto or home, an unknown product type), to dates, to outputs, and to configuration. Coverage is measured as the share of partitions exercised.
4. Boundary value analysis (BVA)
The idea: defects cluster at the edges of partitions, where developers write < when they meant <=. So test the values at and next to each boundary.
For the valid range 16 to 99:
| Approach | Values to test |
|---|---|
| Two-value BVA (each boundary and its nearest neighbour outside) | 15, 16, 99, 100 |
| Three-value BVA (each boundary plus both neighbours) | 15, 16, 17, 98, 99, 100 |
Three-value BVA is stricter: it also catches a boundary that is correct on one side but wrong on the other. Apply the same thinking to other boundaries: the 25-year vehicle age limit, a premium of exactly zero, the last day of a policy term, the first and last character of a field, and 0, 1 and maximum counts for a list.
BVA works on top of EP: EP finds the partitions, BVA picks the edge values within them. A very common mistake is to test the middle of each partition and never the edges.
5. Decision table testing
The idea: when several conditions combine to decide an outcome, a table lists every combination so none is forgotten. Conditions form the rows at the top, outcomes the rows below, and each column is a rule.
Suppose (illustrative) the multi-policy discount applies only when the customer has an active home policy and an active auto policy and no unpaid premium.
| Condition / action | R1 | R2 | R3 | R4 |
|---|---|---|---|---|
| Active home policy | Y | N | Y | Y |
| Active auto policy | Y | — | N | Y |
| No unpaid premium | Y | — | — | N |
| Discount applied | Yes | No | No | No |
A dash (—) means "does not matter", which collapses the table: three conditions have 8 combinations, and these 4 rules cover all of them (R2 covers 4, R3 covers 2, R1 and R4 one each). Each rule becomes at least one test. Decision tables are excellent at exposing gaps and contradictions in the requirement itself: if no one can say what the outcome of a column should be, you have found a requirements defect, long before code. When some combinations are impossible, mark them and confirm with the requirement owner. Coverage is the share of rules tested.
6. State transition testing
The idea: some things behave differently depending on their history. A policy that is active can be cancelled; a cancelled one cannot be endorsed. Model the states, the events that cause transitions, and any conditions and actions. Here is an illustrative policy life cycle:
| From | Event | To |
|---|---|---|
| (start) | a quote is created | Quoted |
| Quoted | bind | Bound |
| Quoted | validity ends | Expired |
| Bound | effective date arrives | Active |
| Active | cancel | Cancelled |
| Active | term ends | Expired |
| Expired | renew | Active |
From the table you derive tests at increasing strength:
- All states: visit every state at least once.
- All transitions (valid): exercise every arrow (also called 0-switch coverage).
- Invalid transitions: try events that should not work (bind an expired quote, endorse a cancelled policy). A state table with every state against every event makes the invalid ones visible: each blank cell is "what should happen here?" and each is a test. Test one invalid transition per test case so a failure is easy to diagnose.
- Sequences: longer paths (quote, bind, cancel, renew) find defects that depend on history.
A real example: binding a quote that is already bound should be refused with 409 Conflict (a conflict with the current state), which is an invalid-transition test passing.
7. Use case and scenario testing
A use case describes a user achieving a goal through a sequence of steps: a main (happy) path and alternative and exception paths. Test the main path first, then each alternative: "Priya requests a quote; the customer already exists; the driver is under 16; the rating service times out." Use cases test the flow across screens and services and are the bridge to acceptance tests, but they usually miss detailed boundaries, so combine them with EP and BVA.
8. White-box techniques: statement and branch coverage
White-box testing looks at the code and measures coverage: how much of it the tests exercised.
if age < 16:
reject() # statement 2
else:
premium = base # statement 3
if multi_policy: # statement 4
premium = premium * 0.9 # statement 5
(Statement 1 is the first if.) There are five statements and four branches (age true, age false, multi true, multi false).
| Tests run | Statement coverage | Branch coverage |
|---|---|---|
| Age 15 | 2 of 5 = 40% | 1 of 4 = 25% |
| Age 15 and age 30 with multi-policy | 5 of 5 = 100% | 3 of 4 = 75% |
| Age 15, age 30 with multi, age 30 without multi | 5 of 5 = 100% | 4 of 4 = 100% |
The middle row is the lesson: 100% statement coverage does not give 100% branch coverage, because the "multi-policy false" path was never taken. Branch coverage is stronger and is the usual target. Coverage tells you what you have not tested; it never proves the tests are good, so a high number with weak assertions is false comfort. Developers usually use white-box techniques at the component level.
9. Combinatorial and pairwise testing
When many inputs each have several values, the combinations explode: a quote with 3 coverage types, 3 usage types and 3 vehicle classes has 3 × 3 × 3 = 27 combinations. Most defects are caused by one input or the interaction of two. Pairwise testing chooses a small set of tests so that every pair of values appears together at least once; for these three inputs, 9 tests do it instead of 27. Tools (PICT, and others) generate the set. Use it for configuration and input combinations that EP and decision tables do not cover, and keep the full set for the highest-risk combinations.
10. Experience-based techniques: layered on top, not instead of
When you have limited documentation or want to find what nobody specified, use your experience.
- Error guessing: list likely mistakes from past defects and common failure patterns, then test them: empty input, very long input, special characters, leading and trailing spaces, a date like 29 February, a negative amount, a duplicate submission, a double click.
- Exploratory testing: simultaneous learning, test design and execution. It is not random clicking: it is structured by a charter (a mission, for example "explore renewal with unusual dates to find rating errors") and run in time-boxed sessions (often 60 to 90 minutes), with notes and a short debrief. It shines on new features and unclear requirements.
- Checklist-based testing: a reusable list of things to check, built from experience and standards (a security checklist, an accessibility checklist). It brings consistency and does not rely on one person's memory.
11. Collaboration-based approaches
Some testing starts before there is anything to run. Collaborative user story writing (the Three Amigos conversation between business, development and testing) and acceptance criteria produce examples that become tests. Acceptance test-driven development (ATDD) turns those examples into automated acceptance tests before the code is written, so the story is done when they pass.
12. Writing a good test case
A test case is only useful if someone else can run it and reach the same verdict.
| Field | Purpose | Example |
|---|---|---|
| ID and title | Identify and describe | TC-31: Quote rejected for driver aged 15 |
| Traceability | The requirement it checks | REQ-12 |
| Preconditions | State needed first | Signed in as underwriter; auto quote form open |
| Test data | Exact inputs | driver_age = 15, other fields valid |
| Steps | What to do, in order | 1. Enter the data. 2. Submit the quote. |
| Expected result | The specific, observable outcome | Quote not created; message "Driver age below minimum" shown |
| Postconditions / cleanup | Leave the system clean | No quote record remains |
Good versus weak:
- Weak: "Test the age field." Which values? What is correct? Nobody can fail it.
- Good: "Submit a quote with driver age 15; expect the message 'Driver age below minimum' and no quote created." Specific, checkable, traceable.
Rules of thumb: one clear purpose per test; expected result decided before you run it (not after you see what happens); include positive and negative cases; keep tests independent so one failure does not hide others; and write them so a stranger could follow them. Prioritise by risk, run the highest-risk ones first, and group related tests to save setup time.
13. Choosing the right technique
No single technique is best; each is strong on a particular shape of problem. A quick guide:
| If the thing you are testing is... | Start with | Then add |
|---|---|---|
| A field or value with a valid range | Equivalence partitioning | Boundary value analysis |
| Several conditions combining into one outcome | Decision table | Boundary values on each condition |
| Behaviour that depends on history or status | State transition testing | Invalid-transition tests |
| A user goal across several screens or services | Use case or scenario testing | EP and BVA on the key inputs |
| Many inputs, each with a few values | Pairwise testing | Full combinations only for the riskiest |
| Code you wrote or inherited | Branch coverage | Review the branches no test reaches |
| Unclear or new behaviour | Exploratory testing with a charter | Turn what you learn into written tests |
Apply risk to decide how many techniques to stack: a high-risk rule such as eligibility earns EP, BVA and a decision table; a low-risk banner earns one quick check.
14. A worked example: from one requirement to a set of tests
Take this requirement: "When a quote is submitted for a driver aged under 16, the system shall reject it within 2 seconds and show the message 'Driver age below minimum'. Drivers aged 16 or over are not rejected for age."
Analysis (test conditions): age below 16 is rejected; age 16 or over is accepted; the message is correct; the response is fast enough; an invalid age (blank, text) is handled.
Design (techniques applied):
| Test | Technique | Input | Expected result |
|---|---|---|---|
| T1 | EP: below minimum | age 10 | Rejected, message "Driver age below minimum" |
| T2 | BVA: just below the boundary | age 15 | Rejected, same message |
| T3 | BVA: on the boundary | age 16 | Accepted (not rejected for age) |
| T4 | BVA: just above | age 17 | Accepted |
| T5 | EP: typical valid | age 40 | Accepted |
| T6 | EP: invalid, not a number | "abc" | Rejected with a clear validation message, no server error |
| T7 | EP: invalid, empty | (blank) | Rejected with a clear validation message |
| T8 | NFR: response time | age 15 | Message shown within 2 seconds |
| T9 | Error guessing | age -1, 0, 15.5 | Rejected or handled safely, never a crash |
Nine tests give complete partition and boundary coverage of this rule, and every test traces to the one requirement. Compare that with a single "enter an age under 16" test, which would miss the boundary, the invalid inputs and the speed requirement. Note T3: the most valuable test is often the one on the boundary.
15. Using AI to draft test cases
AI can speed up the first draft. In SQValex's test management tool, Draft with AI proposes test cases from a requirement. It is good at brainstorming: it often suggests error cases and combinations you had not listed.
It is not a substitute for the techniques. Treat its output as a draft to review:
- Trace each case back to a requirement. Delete those that do not trace.
- Check the expected results. AI can invent a rule or a message that sounds right but is not in your requirement.
- Look for gaps. Did it cover every partition, every boundary, every rule in the decision table, every invalid transition? Add what is missing.
- Remove duplicates and tests that check the same thing.
- Make data specific. "A young driver" is not test data; "age 20" is.
A good prompt gives the requirement, the technique you want ("use boundary value analysis on the age range 16 to 99, three-value"), the output format, and asks it to state its assumptions. The best use is to apply a technique yourself and let AI check your work for gaps, not the other way round.
16. Common mistakes
- Testing the middle of each partition and never the boundaries.
- Skipping invalid partitions and invalid transitions.
- Expected results like "works correctly" or "no error".
- Many tests that all check the same thing, and none for an untested rule.
- Treating 100% statement coverage as "fully tested".
- Writing tests that depend on each other's order or leftover data.
- Accepting AI-generated cases without tracing and checking them.
- Using only formal techniques, or only exploratory, instead of both.
17. Check yourself
- A field accepts ages 16 to 99. List the two-value BVA tests. 15, 16, 99, 100.
- What is the benefit of equivalence partitioning? Far fewer tests, because one value stands for a whole partition.
- A decision table has 3 yes/no conditions. How many combinations before collapsing? 8.
- Which technique finds problems that depend on history, such as binding a cancelled quote? State transition testing.
- Can you have 100% statement coverage but less than 100% branch coverage? Yes: a branch that is never taken (such as an
ifthat is always true) leaves statements covered but a branch missed. - What is a test charter? A short mission that guides an exploratory session, such as "explore renewal with unusual dates".
- Why decide the expected result before running the test? Otherwise you will tend to accept whatever the system does.
- How many pairwise tests cover three inputs with three values each? About 9, instead of 27.
18. Interview questions, with short answers
- Explain equivalence partitioning and boundary value analysis with an example. EP groups inputs treated alike and tests one per group; BVA tests the edges of each group, for example 15, 16, 99 and 100 for an age range of 16 to 99.
- When would you use a decision table? When several conditions combine to decide an outcome, to be sure no combination is missed and to expose gaps in the requirement.
- What is the difference between black-box and white-box testing? Black-box derives tests from behaviour and requirements; white-box from the code's structure and measures coverage.
- How do you test something with no documentation? Exploratory testing with charters and notes, error guessing, and talking to users and developers; then write down what you learn.
- What makes a good test case? Specific inputs, a specific expected result decided in advance, traceability to a requirement, independence, and clarity for another person.
- How would you use AI when designing tests? To brainstorm and to check for gaps, with every case traced and its expected result verified by a person.
Practise it
- For driver age and vehicle year, write EP and three-value BVA test cases, including the value directly on each boundary, not just its neighbours.
- Build a full decision table for multi-policy discount eligibility, including infeasible or "no defined action" combinations that you resolved with the requirement owner.
- Write state-transition test cases covering every valid status transition, plus at least two invalid ones (one per test case).
- Write one exploratory charter for a feature you have not designed tests for yet.
In our AI-Led Quality Engineering course this is Week 4: you apply every technique above to a live insurance application, and the work is checked by code. For the AI side of testing, read AI in software testing, and how to test AI systems.
Frequently asked questions
What is equivalence partitioning?
A technique that divides inputs into groups the system should treat the same way and tests one representative from each group, so a handful of tests stand for thousands of possible values.
What is boundary value analysis with an example?
It tests the values at and next to the edges of a range. For a valid age range of 16 to 99, two-value BVA tests 15, 16, 99 and 100, and three-value BVA adds 17 and 98.
How many tests does pairwise testing need for three inputs with three values each?
About 9 instead of all 27 combinations, because it makes every pair of values appear together at least once.
Can you have 100% statement coverage but less than 100% branch coverage?
Yes. A branch that is never taken, such as an if condition that is always true, leaves every statement covered but a branch missed.