Test Case Design
Systematic techniques for deriving test cases from requirements. The goal is maximum defect detection with minimum test cases.
Systematic techniques for deriving test cases from requirements. The goal is maximum defect detection with minimum test cases. Ad-hoc testing finds bugs, but technique-driven testing finds bugs efficiently and repeatably.
Equivalence Partitioning (EP)
Divide inputs into groups (partitions) where all values in a group are expected to behave the same. Test one value per partition, if one fails, all will fail; if one passes, all will pass.
Rule: For each partition, test one valid and one invalid value.
Example: Age field (must be 18–65)
| Partition | Range | Example value | Expected |
|---|---|---|---|
| Below minimum | < 18 | 15 | Reject |
| Valid | 18–65 | 30 | Accept |
| Above maximum | > 65 | 70 | Reject |
| Non-numeric | letters, symbols | "abc", -1 | Reject |
| Boundary (EP) | 18, 65 | 18, 65 | Accept |
Test cases: {15, 30, 70, "abc"}. Four tests cover four partitions. Without EP you might test 100 ages and miss the boundary.
Boundary Value Analysis (BVA)
Errors cluster at boundaries. Test the boundary values and their immediate neighbours.
For a range min–max, test: min-1, min, min+1, max-1, max, max+1
Example: Password length (6–20 characters)
| Value | Input | Expected |
|---|---|---|
| min - 1 | 5 chars | Reject |
| min | 6 chars | Accept |
| min + 1 | 7 chars | Accept |
| max - 1 | 19 chars | Accept |
| max | 20 chars | Accept |
| max + 1 | 21 chars | Reject |
BVA extends EP. Instead of one test per partition, test the partition edges.
Combined EP + BVA approach (industry standard):
- Identify partitions (EP)
- Test boundaries of each partition (BVA)
- Test one mid-partition value for sanity
Decision Tables
For features with combinations of conditions and rules. Maps every combination of inputs to an expected action.
Example: Insurance premium calculator
| Condition | T1 | T2 | T3 | T4 |
|---|---|---|---|---|
| Age > 25? | Y | Y | N | N |
| Clean record? | Y | N | Y | N |
| Action | ||||
| Low premium | ✓ | |||
| Medium premium | ✓ | ✓ | ||
| High premium | ✓ |
Four test cases cover all combinations. For n binary conditions, a full decision table has 2ⁿ columns. For large n, reduce using risk-based pruning (focus on combinations most likely to differ in behaviour).
State Transition Testing
For systems with states and events that trigger transitions. Model as a state diagram; derive tests that traverse each state and each transition.
Example: Order lifecycle
[New] --pay--> [Paid] --ship--> [Shipped] --deliver--> [Delivered]
| |
|--cancel--> [Cancelled] [Paid] --cancel--> [Refunded]
Test cases:
- Happy path: New → Paid → Shipped → Delivered
- Cancel before payment: New → Cancelled
- Cancel after payment: New → Paid → Refunded
- Invalid: attempt to ship a New order (should error)
- Invalid: attempt to cancel a Delivered order (should error)
Cover every valid transition (positive) and at least one invalid transition per state (negative).
Use Case Testing
Derive tests from use cases or user stories. Each use case has a basic flow (happy path) and alternate/exception flows.
Use case: User login
| Flow | Steps |
|---|---|
| Basic | Valid credentials → logged in, redirected to dashboard |
| Alt 1 | Wrong password → error message, counter incremented |
| Alt 2 | Account locked (5 failed attempts) → locked message, no login |
| Alt 3 | Password expired → redirect to reset flow |
| Alt 4 | MFA required → MFA challenge shown |
| Exception | DB unavailable → friendly error, no stack trace |
Pairwise / All-Pairs Testing
For parameters with many possible values, test all two-way combinations rather than all combinations. Reduces N^k tests to ~N*k tests.
Example: Test a form with 3 parameters, 3 values each — full combination: 27 tests. Pairwise: 9 tests, covering every pair of values at least once.
Tool: PICT (Pairwise Independent Combinatorial Testing) by Microsoft.
Writing Good Test Cases
Structure (GIVEN-WHEN-THEN):
GIVEN I am on the checkout page
AND I have 3 items in my cart
WHEN I click "Place Order" without a payment method
THEN an error message "Please add a payment method" is shown
AND the order is not created
A good test case:
- Has a single, specific expected outcome (no "verify the page looks right")
- Is repeatable by any team member following the steps
- Is independent — doesn't require previous tests to have run
- Has clear test data specified (not "enter a valid email" — enter
test@example.com) - Has a clear pass/fail criterion
Test case metadata:
- ID (TC-001)
- Title
- Priority (Critical/High/Medium/Low)
- Type (Positive/Negative/Boundary)
- Preconditions
- Steps
- Expected result
- Linked requirement
Negative Testing Checklist
For any input field, always test:
- Empty/null/blank
- Whitespace only
- Maximum length exceeded
- Special characters (
<>'"&;) - SQL injection patterns (
' OR '1'='1) - Script injection patterns (
<script>alert(1)</script>) - Unicode edge cases (emoji, right-to-left text)
- Very large numbers, negative numbers
- Decimal values where integer expected
- Future dates where past dates expected
Common Failure Cases
Equivalence partitions overlap because boundaries are not defined precisely Why: a partition defined as "valid age: 18-65" and another as "above maximum: >= 65" includes 65 in both partitions, making the boundary test ambiguous and potentially testing the wrong behaviour. Detect: two test cases with values at the exact boundary produce contradictory expected results, or a partition table has a value that fits two partition definitions. Fix: define partitions as strictly non-overlapping ranges using exclusive upper bounds or explicit membership rules before writing any test cases.
BVA applied to non-continuous domains, producing meaningless boundary tests Why: BVA is applied to categorical or enum fields (e.g., status: pending/active/closed) where "min-1" and "max+1" have no meaning, generating invalid test values that the system correctly rejects. Detect: the boundary test for a categorical field is testing an empty string or a non-existent enum value that is trivially rejected by input validation rather than business logic. Fix: apply BVA only to ordered ranges (numeric, date, string length); use equivalence partitioning and decision tables for categorical inputs.
Decision table has missing combinations because n conditions imply 2^n columns
Why: a decision table for 4 binary conditions requires 16 columns, but only 5 are written because the rest seem "obviously the same," leaving untested edge-case combinations.
Detect: running pairwise analysis (PICT) against the incomplete table reveals pairs of conditions that are never combined in any test case.
Fix: generate the full 2^n table first, then prune identical-action columns using a risk-based approach — only prune combinations where the action is identical AND the underlying code path is confirmed to be the same.
State transition test covers only valid transitions, missing the invalid ones Why: testers write the happy-path transitions but skip testing invalid transitions (e.g., shipping a New order) because they seem obviously wrong. Detect: a code change accidentally removes a guard for an invalid transition, which ships undetected because no test exercised that path. Fix: for each state, write at least one test for every transition that should be rejected; assert both the error response and that the state did not change.
Connections
- qa/test-strategy — where test case design fits in the overall test approach
- qa/exploratory-testing — unscripted complement to scripted test case design
- qa/bdd-gherkin — GIVEN/WHEN/THEN format for acceptance test cases
- qa/risk-based-testing — prioritise which test cases to write first
- qa/bug-lifecycle — what happens when a test case fails
Open Questions
- What testing scenarios does this technique systematically miss?
- How does this approach need to change when delivery cadence moves to continuous deployment?
Related reading