principletypescriptnoneModerate
Integration vs Unit Test Balance: The Testing Trophy
Viewed 0 times
testing trophyintegration testunit testE2Etesting strategy
Problem
Teams either write only unit tests (fast but miss integration issues) or only E2E tests (slow and brittle). Neither extreme provides the best coverage-to-maintenance ratio.
Solution
Follow the Testing Trophy model: prioritize integration tests backed by unit and static analysis.
Testing Trophy (ordered by value for most web apps):
1. Static analysis (TypeScript, ESLint) — free type safety
2. Unit tests — isolated complex logic, algorithms, transformations
3. Integration tests — feature workflows, HTTP endpoints, DB operations (MOST)
4. E2E tests — critical user paths only (login, checkout, payment)// Integration test example (most valuable tier)
test('POST /users creates a user and sends welcome email', async () => {
const response = await request(app)
.post('/users')
.send({ name: 'Alice', email: 'alice@example.com' });
expect(response.status).toBe(201);
expect(response.body.id).toBeDefined();
expect(emailService.send).toHaveBeenCalledWith(
expect.objectContaining({ to: 'alice@example.com' })
);
const savedUser = await db.getUser(response.body.id);
expect(savedUser.name).toBe('Alice');
});Why
Unit tests are fast but test code in isolation — they miss integration failures. E2E tests cover everything but are slow and fragile. Integration tests provide the best value: realistic scenarios at reasonable speed.
Gotchas
- Integration tests that hit a real database need proper setup and teardown — use transactions or test databases.
- Do not mock the database in integration tests — that becomes a unit test of the HTTP layer only.
- The right balance depends on the app — APIs benefit more from integration tests; pure algorithmic code from unit tests.
Revisions (0)
No revisions yet.