← Concepts

阅读中文版本

Unit Test Boundaries

Unit test boundaries decide what counts as one unit — a function, a class with its collaborators, or a module — trading isolation and speed against mocking depth and behavioral fidelity.

testing

Definition

The unit boundary is the scope a unit test exercises without external infrastructure. Solitary testing isolates the unit behind test doubles for all collaborators; sociable testing runs the unit with its in-process collaborators real. Narrow boundaries maximize speed and pinpoint failures; wider boundaries mock less and catch integration assumptions, at the cost of larger failure blast radius.

Context and scope

A design decision per module, famously articulated by Fowler as solitary versus sociable testing. Shapes the pyramid composition and the mocking strategy of the suite.

Common misconceptions

  • Unit means one class in isolation — the Detroit school runs clusters with real collaborators; both are unit tests with different boundaries
  • More isolation is always better — heavy mocking couples tests to implementation structure, so refactors break tests without behavior changing
  • Boundaries are set project-wide — per-module choice fits better: algorithms want narrow, orchestration wants sociable

Anti-patterns

  • Mocking every collaborator of every class and rebuilding the suite after each refactor
  • Testing through the whole application for every case and calling it unit testing
  • Choosing boundaries by fashion rather than by change and failure patterns of the module

Related concepts

Related examples

Authoritative source

https://martinfowler.com/articles/unitTest.html

What it is

Every test answers two questions: how much does it execute, and what does it replace. The unit boundary is the line between them. Draw it tight and tests are fast and precise but coupled to structure; draw it wide and tests survive refactors but fail farther from the cause.

How it works

Solitary style replaces collaborators with doubles: databases, queues, clocks. Assertions target interactions and state of the unit alone. Sociable style keeps in-process collaborators real and replaces only true boundaries — time, randomness, I/O. Hybrid suites put algorithms under solitary tests and orchestration under sociable ones.

When to choose

Refactor-heavy domains favor sociable tests that outlive structure; contract-heavy domains favor solitary tests pinning each side of an interface. Watch the feedback loop: slow tests or noisy failures indicate the boundary sits at the wrong level.

Pitfalls

Mock-driven tests verify calls, not outcomes — they pass while real collaborators misbehave. Sociable tests amplify blast radius: one constructor bug reddens hundreds of tests. The boundary decision ages: modules drift from algorithmic to orchestration shape, and boundaries set at birth misfit adulthood.