Unit, Integration, and System Testing
Tests form a pyramid: many fast checks of small parts, fewer checks of their assembly, and a handful of end-to-end runs.
Three Scales of Test
Unit tests exercise the smallest testable pieces, a single function or class, in isolation. Integration tests check that units cooperate correctly across their interfaces. System tests run the full pipeline end to end, as a user would. Each scale catches faults the others miss.
The Test Pyramid
A common heuristic: have many unit tests, fewer integration tests, and only a small number of system tests. Unit tests are fast, precise about where a fault lives, and cheap to run on every change. System tests are slow and localize faults poorly, but they alone confirm the whole assembly does the intended job. An inverted pyramid, mostly slow end-to-end tests, gives late and vague feedback.
What Each Reveals
- Unit: logic errors, boundary conditions, and off-by-one faults inside one component.
- Integration: interface mismatches, wrong units, and incorrect data handoff between components.
- System: emergent failures that appear only when everything runs together, including performance and memory.
Isolation and Test Doubles
Unit tests isolate the code under test by replacing its dependencies with simple stand-ins, called stubs or mocks, so a failure points to one place. Integration tests deliberately remove those stand-ins to test the real seams. Knowing which to isolate and which to exercise for real is a core testing skill.
In Scientific Codes
A physics pipeline that couples an equilibrium solver, a transport model, and a heating module needs all three scales: unit tests on each solver, integration tests on the coupling handoffs where units and conventions are easily mismatched, and system tests that a full case reproduces a trusted reference. The coupling seams are where subtle errors hide, so integration coverage there earns its keep.