Introducing the 12 Factors for Good Tests

Most tests suck.
Yours might too.

Learn how to fix them with the 12 Factors methodology and real examples of what NOT to do.

The 12 Factors for Good Tests

A methodology for building test suites that are fast, reliable, and actually useful.

01

Isolation

Tests are hermits

02

Clarity

Test names are documentation

03

Speed

Fast tests get run, slow tests get skipped

04

Determinism

Flaky tests are worse than no tests

05

Focus

One test, one concern

06

Portability

No 'works on my machine'

07

Resilience

Tests adapt to refactoring

08

Maintenance

Delete bad tests ruthlessly

09

Boundaries

Mock the edges, not the core

10

Data

Test data tells a story

11

Diagnostics

Failures should scream what's wrong

12

Depth

Coverage ≠ quality

Get a taste of the horror

Testing Implementation, Not Behavior

😱 This Will Haunt Your CI
// 😱 BAD: Testing internal implementation
test('user service', () => {
  const userService = new UserService();
  const spy = jest.spyOn(userService, 'validateEmail');
  
  userService.createUser('john@example.com', 'password');
  
  expect(spy).toHaveBeenCalledWith('john@example.com');
  expect(userService.users.length).toBe(1);
});
✅ Actually Useful Test
// ✅ GOOD: Testing behavior and outcomes
test('creates user with valid email', async () => {
  const result = await createUser('john@example.com', 'password');
  
  expect(result.success).toBe(true);
  expect(result.user.email).toBe('john@example.com');
  
  const user = await findUserByEmail('john@example.com');
  expect(user).toBeDefined();
});

Ready to write tests that don't suck?

Join thousands of developers learning to write better tests through brutal honesty and practical examples.

Start Learning