Q1 of 38 · Test design
What is equivalence partitioning?
Short answer
Short answer: A test design technique that groups inputs into classes which are expected to behave the same, then picks one representative from each class. It cuts hundreds of input cases down to a handful without losing coverage of distinct behaviours.
Detail
Equivalence partitioning rests on a simple observation: not every input deserves its own test. If a function accepts integers from 1 to 100 and rejects everything else, you don't need 100 tests for valid inputs. Pick one — say, 50 — and one each from the invalid classes (≤ 0 and ≥ 101). The function should treat every member of an equivalence class the same way; representative coverage of the class is enough.
Concretely, for an "age" field accepting 18–120:
- Valid class: 18 ≤ age ≤ 120 → one test (age = 35).
- Below valid: age < 18 → one test (age = 12).
- Above valid: age > 120 → one test (age = 150).
- Wrong type: non-numeric → one test ("abc").
- Missing: empty → one test (null).
Five tests instead of hundreds, and each tests a distinct behavioural class. The companion technique is boundary value analysis, which adds tests at the edges of each class (17, 18, 120, 121) because off-by-one errors are common at boundaries. Most practitioners use both together.
The catch: the partitions are only valid if your assumption that "the class behaves uniformly" is right. If the function has special handling for, say, age 65 (senior discount), 65 deserves its own class. Equivalence partitioning is design done up front, with the spec — not a substitute for thinking.
// EXAMPLE
age-validator.test.ts
import { describe, test, expect } from 'vitest';
import { validateAge } from './age-validator';
describe('validateAge — equivalence partitioning', () => {
// Valid class: representative
test('accepts a typical adult age', () => {
expect(validateAge(35)).toEqual({ ok: true });
});
// Below-valid class: representative
test('rejects an under-18 age', () => {
expect(validateAge(12)).toEqual({
ok: false, error: 'TOO_YOUNG',
});
});
// Above-valid class: representative
test('rejects an above-120 age', () => {
expect(validateAge(150)).toEqual({
ok: false, error: 'TOO_OLD',
});
});
// Wrong type
test('rejects a non-numeric value', () => {
expect(validateAge('abc' as unknown as number)).toEqual({
ok: false, error: 'INVALID_TYPE',
});
});
// Boundary tests (BVA, complementary)
test.each([
[17, false], [18, true], [120, true], [121, false],
])('boundary: age %i → ok=%s', (age, expected) => {
expect(validateAge(age).ok).toBe(expected);
});
});// WHAT INTERVIEWERS LOOK FOR
// COMMON PITFALL
// Related questions