Why Testing Every Value Is Not Testing More
A discount field accepts ages 18 to 65 — 'enter 100 values, cover everything' is the instinct of a diligent tester, and it is the wrong instinct. The values 19, 20, 21, ... 64 all exercise the same decision in the code: if (age >= 18 && age <= 65). A bug in that condition will make every value in the range fail identically or pass identically. Testing ten values from the range tells you almost exactly as much as testing a hundred. Equivalence partitioning is the technique that turns this observation into a systematic method: group inputs into classes where the software is expected to behave the same way, then test one representative per class.
The spec of the discount field defines the classes:
Requirement: customers aged 18-65 get 10% discount; others get none.
Valid partitions: Invalid partitions:
P1: 18 ≤ age ≤ 65 I1: age < 18
I2: age > 65
I3: age is not a number (letters, symbols)
I4: age is empty / missing
Each invalid class needs its own partition because each expects a different handling path: a negative age should be rejected by validation, a letter should fail type parsing, and an empty field should trip the required-field check. Collapse them into one 'invalid input' class and you lose exactly the coverage that catches invalid-input handling gaps — the most common defect family this technique finds.
From the partitions, the minimal suite is one representative per class — five cases instead of a hundred:
| Case | Input | Expected |
|---|---|---|
| P1 | 30 | Discount applied |
| I1 | 17 | No discount, 'under 18' path |
| I2 | 66 | No discount |
| I3 | abc |
Validation error, field rejected |
| I4 | (empty) | Required-field error |
The hypothesis behind each pick is explicit: if the software handles one value of a class correctly, it handles the whole class (and if it mishandles one, the whole class is suspect). That is what makes the technique defensible in review — you are not sampling randomly; you are sampling by behavior.
The technique transfers directly to other input types. Dates: a booking window of 2026-01-01 to 2026-12-31 partitions into before-window, in-window, after-window, plus invalid calendar dates (2026-02-30) and wrong formats (31/12/2026 vs 2026-12-31). Dropdowns and enumerations: each option is a class — and 'none selected' plus 'value from a stale API list' are the invalid classes testers forget. Booleans and checkboxes: checked, unchecked, and the tri-state cases (indeterminate in a bulk-select list). Even free-text fields partition: empty, whitespace-only, one character, at max length, over max length, with control characters — each class hits a different branch of the validation code.
Where interviewers push: 'why is one value per class enough?' The answer admits the limits — the technique assumes the implementation branches on class membership, not on individual values; it says nothing about the boundaries between adjacent classes (that is boundary value analysis, the next topic); and it does not cover combinations of inputs (that is decision tables and pairwise). One value per class is enough for this technique's hypothesis, and knowing exactly what it does not cover is what a strong answer adds.
Deriving Partitions From a Vague Requirement: A Worked Method
The discount field above had a crisp spec. Real requirements rarely do: 'Users can upload profile photos up to 5 MB in JPG or PNG format.' Five words in that sentence hide an input domain, and partitioning is how you unpack it. The method has three passes.
Pass 1 — read every constraint as an axis. The sentence constrains size (≤ 5 MB), format (JPG/PNG), and implicitly existence (a photo is present). Each constraint becomes a partitioned dimension:
Size: valid: 1 byte – 5 MB (5,242,880 bytes)
invalid: 0 bytes · over 5 MB · negative (API call, not UI)
Format: valid: .jpg · .png
invalid: .gif · .heic · .exe renamed to .jpg · no extension
Presence: valid: file attached
invalid: nothing attached · 'choose file' clicked then cancelled
Pass 2 — challenge each class with the question 'does the software treat these differently?'. This is where domain knowledge earns its keep. '0 bytes' versus 'a 1-byte file' genuinely differ — one is a truncated upload, the other is a tiny valid file; keep both. 'gif' and 'heic' both hit the same 'unsupported type' branch; one representative (gif) suffices unless the spec lists per-type error messages. And your list should include classes nobody wrote down: a .jpg file whose actual content is a ZIP (magic-number validation vs extension validation — a real, recurring security bug), a file exactly at 5 MB (boundary — flagged for the next topic), and a filename with unicode or path separators (input handling beyond the visible spec).
Pass 3 — assign one representative and state the expected behavior per class. The expected behavior is the deliverable, not the input list:
| Class | Representative | Expected |
|---|---|---|
| Valid size+format | 200 KB .png | Upload succeeds, preview renders |
| Over size | 6 MB .png | 'File too large (max 5 MB)' |
| Zero bytes | empty file | 'File appears empty' or upload error |
| Wrong format | 100 KB .gif | 'Use JPG or PNG' |
| Content mismatch | .jpg that is a ZIP | Rejected by content sniffing |
| Not attached | (none) | 'Choose a photo' prompt |
Writing the expected column is the technique's real value: it turns the partition table into reviewable specification, and the product owner reading it often amends the requirement on the spot ('actually we allow GIFs too'), which is a requirement defect found by test design — exactly the shift-left economics from Agile Testing and Shift-Left.
Two failure modes mark inexperienced partitioning. Under-partitioning: one 'valid' and one 'invalid' class for a multi-constraint input — the five-case upload suite becomes two cases and the per-constraint handling gaps go untested. Over-partitioning: thirty classes for a dropdown of five options, each its own case, producing a suite that costs more to maintain than the feature. The calibration question both fail to ask: does this class hit a different branch of the implementation? If yes, partition it; if no, one representative covers it.
Where Partitions Alone Stop: Pairing With Boundaries and Combinations
Equivalence partitioning has a structural blind spot, and it is worth internalizing before an interviewer finds it for you: partitions assume behavior is constant inside a class and change only between classes — and the most defect-prone values are the ones right on the class edges. The age >= 18 implementation may accept 18 and reject 17 correctly while still being wrong at exactly the boundary of the age <= 65 check — a partition suite testing 30, 17, and 66 never notices. This is why EP pairs with boundary value analysis: keep the partition structure, then test the edges of each class. The combined suite for the discount field:
Partitions: P1 [18..65] · I1 (..17] · I2 [66..]
Combined suite (EP + BVA):
17, 18, 19 ← min boundary: below, at, above
64, 65, 66 ← max boundary: below, at, above
abc, (empty) ← non-numeric partitions from EP
7 cases, and every realistic off-by-one bug in this field is caught.
Notice the arithmetic of value: partitions alone gave 5 cases and caught wrong-branch bugs; adding the six boundary values adds 6 cases and catches off-by-one bugs — the two highest-yield defect families in input handling, at 11 cases total. A brute-force sweep would have needed a hundred to cover the same ground probabilistically. That comparison — cases written versus defect classes covered — is the currency of test design technique interviews, and it is how you justify suite size to a product manager who asks why QA needs 11 cases for one field.
The second blind spot is combinations. A flight search has departure date, return date, cabin class, and passenger count; EP partitions each axis independently, but a defect like 'return date before departure date is accepted when cabin = business' lives in the interaction of axes. Decision tables (for logical rules across conditions) and pairwise testing (for interaction coverage across many parameters) are the techniques that take over there — EP defines the classes per axis, and those techniques decide which cross-axis combinations deserve cases. Recognizing which technique fits which defect family is itself interview material: single-input handling → EP; edge values → BVA; condition logic → decision tables; many-parameter configurations → pairwise.
A practical workflow that uses all of it: partition each input (EP), mark the edges of each partition for boundary checks (BVA), list condition combinations for the feature's rules (decision table), then generate pairwise combinations if parameters exceed two or three axes. In code-review terms, this maps to what the implementation actually contains: branch conditions, range checks, boolean logic, and configuration matrices — you are reading the code's shape backwards into the suite. Practice the first step on any form you use today: five minutes partitioning a real signup form usually exposes two or three invalid-input classes the live suite does not cover, which is both a portfolio artifact and the fastest way to make the technique automatic.
A closing note on how these techniques appear in automation code: partition tables map naturally to parameterized test fixtures — one test function, a data table with one row per class, expected outcome per row. When a new invalid class is discovered in production, the repair is a new row, not a new test, and the suite's structure stays proportional to the input domain's structure. This is why interviewers sometimes ask you to sketch test cases as data rather than as prose: the data form is the automation form, and a tester who already thinks in rows arrives at the automated suite design a step ahead.
Quiz
1. A field accepts ages 18-65 for a discount. Which input set is the correct equivalence-partition-derived suite (before boundary additions)?
2. Why must invalid inputs usually be partitioned into multiple classes rather than one 'invalid' class?
3. A photo upload spec says 'up to 5 MB, JPG or PNG'. Which partition is derived by challenging 'does the software treat these differently?', not written in the spec?
4. What is the main structural blind spot of equivalence partitioning, and how is it addressed?
Flashcards
Question
What is an equivalence class, and what justifies testing only one value from it?
Click to reveal answer
Answer
An equivalence class is a subset of an input domain where every member is expected to trigger the same handling path in the software (same branch, same outcome). One representative suffices under the hypothesis that if the implementation mishandles one member, it mishandles the class — and if it handles one, the class shares the behavior. The hypothesis fails at class edges (hence BVA) and for value-specific logic.
Question
How do you partition a multi-constraint requirement like 'photos up to 5 MB, JPG or PNG'?
Click to reveal answer
Answer
Treat each constraint as an axis: size (valid 1B–5MB; invalid zero, over-max), format (valid jpg/png; invalid gif/heic/no-extension), presence (attached vs none vs cancelled). Then challenge each class with 'does the software treat these differently?' — adding derived classes like content-mismatch (.jpg that is a ZIP) — and assign one representative plus an explicit expected behavior per class.
Question
Under-partitioning vs over-partitioning: symptoms and the calibration question.
Click to reveal answer
Answer
Under-partitioning: one valid + one invalid class for a multi-constraint input; symptom: per-constraint handling gaps ship untested. Over-partitioning: dozens of classes where the implementation shares one branch; symptom: maintenance cost outweighs coverage. Calibration question for every proposed class: 'does this class hit a different branch of the implementation?' Split yes, merge no.
Question
Give the combined EP+BVA suite for an age field valid 18-65.
Click to reveal answer
Answer
17, 18, 19 (min boundary below/at/above), 64, 65, 66 (max boundary), plus non-numeric and empty partitions from EP — 11 cases total. This catches both wrong-branch bugs (invalid handling) and off-by-one bugs (boundary slips) at a fraction of exhaustive cost.
Question
Which test design technique fits which defect family?
Click to reveal answer
Answer
Single-input handling → equivalence partitioning; edge/off-by-one values → boundary value analysis; combinations of logical conditions → decision tables; state sequences → state transition testing; many-parameter configurations → pairwise. EP defines per-axis classes that the interaction techniques (decision tables, pairwise) then combine.
Revision Notes
Key Takeaways
- 1. One representative per class is enough because members of an equivalence class share a handling path — the hypothesis is behavioral, not random sampling
- 2. Invalid inputs need their own classes per failure path: range check, type parsing, required-field, and content validation are different branches
- 3. The expected-behavior column turns a partition table into reviewable spec and routinely finds requirement defects during refinement
- 4. EP's blind spot is class edges — pair every partition with boundary values to catch off-by-one defects cheaply
- 5. Which technique fits which defect family is the real interview test: EP for input handling, BVA for edges, decision tables for condition logic, pairwise for parameter interactions
Interview Tips
- • "Design test cases for an input field." — narrate the method: list constraints as axes, derive valid and per-path invalid classes, one representative each with expected behavior, then say you would add boundary values next; process beats a random case list
- • "Why is one value per class sufficient?" — state the shared-handling hypothesis, then immediately name where it fails (class edges, value-specific logic); naming the limits signals mastery rather than recitation
- • "Valid 18-65 — give me the suite." — 17/18/19, 64/65/66 plus non-numeric and empty; then justify the size: two defect families (wrong branch + off-by-one) covered in 11 cases
- • "What does equivalence partitioning miss?" — boundaries (BVA), condition combinations (decision tables), parameter interactions (pairwise); positioning EP as the first step of a design toolkit scores higher than presenting it as complete
Cheat Sheet
Equivalence Partitioning
Definition: partition an input domain into classes expected to behave identically; test one representative per class.
Age 18-65 example:
| Class | Rep | Expected |
|---|---|---|
| Valid [18..65] | 30 | Discount |
| Invalid (..17] | 17 | No discount |
| Invalid [66..) | 66 | No discount |
| Invalid non-numeric | abc | Validation error |
| Invalid empty | — | Required-field error |
Three-pass derivation: (1) read every constraint as an axis (size/format/presence); (2) challenge each class — 'does the software treat these differently?' (adds 0-byte, content-mismatch, unicode-filename classes); (3) write representative + expected behavior per class (the table becomes reviewable spec — product often amends the requirement on the spot).
Calibration: split a class only if it hits a different implementation branch; merge otherwise. Under-partitioning hides validation gaps; over-partitioning inflates maintenance.
Blind spots → pairing: class edges (off-by-one) → BVA; cross-input interactions → decision tables / pairwise. EP defines the per-axis classes those techniques combine.
Value metric: cases written vs defect classes covered — EP+BVA ≈ 11 cases for the age field vs ~100 exhaustive values.