Test Doubles and Testing at a Boundary
To test code that talks to a database, a clock or a network, the test replaces that neighbour with a stand-in it controls. The choice of where to put the seam decides whether the test survives a refactoring or breaks on every change.
What a learner can do afterwards
- Replace a real dependency with a stand-in and test the logic around it
- Distinguish a stub that returns canned answers from a mock that checks calls
- Explain why a test that asserts on internal calls breaks during refactoring
1 · Read
You already know a unit test checks one small piece of code. When that code talks to a database, a clock, or a network, you replace the neighbour with a stand-in you control. The seam is the place where you plug the stand-in in.
A function greets you differently before and after noon by reading the clock. In the test you swap the real clock for a fixed one that always says 9 in the morning. Now the result is predictable and the test never depends on the hour.
A stub is a stand-in that returns canned answers, such as a database that always returns the same row. A mock is a stand-in that also records which calls it received, so the test can check the code asked for the right thing.
Put the seam at the boundary of your code, and check the outward result rather than every internal call. Tests that assert on internal calls break on every refactoring, while tests on results survive it.
Replace awkward neighbours with stand-ins at the boundary, and check results instead of calls so refactors survive.
2 · Watch
Take it off screen
Where it sits
8 questions wait behind this lesson, each with its answer explained. Every answer feeds the sky: stars light as they are learned, and dim when it is time to come back.