Test Doubles and Testing at a Boundary
A test double replaces a dependency with a stand-in the test controls. A seam allows that substitution. Checking public results and contract-relevant boundary interactions can reduce dependence on internal structure.
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 how assertions tied to private helpers can break during behaviour-preserving refactoring
1 · Read
A test double is a stand-in for a dependency such as a database, clock or network client. A seam is a place where the test can substitute it. Use a double when controlling the dependency helps test your logic. It must supply the interface and behaviour relevant to that test, not reproduce the whole real system.
Suppose a greeting function reads an hour through a clock dependency. A stub clock returns a chosen hour without reading wall time. Returning 9 lets the test exercise the before-noon case whenever it runs. Other uncontrolled dependencies could still affect the result.
A stub supplies chosen responses. A mock supports checking interactions, such as which request was made. One test-double object can do both jobs: return a chosen row and record calls. These names describe testing roles; recording is not a capability exclusive to mocks.
For time-dependent greeting logic, put a seam where the logic obtains the hour. Pass in a clock object or function with the expected interface. The test can then supply a fixed hour while leaving the greeting logic under test. A seam inside formatting code would not control the time source.
An interaction check is useful when an outward request is part of the contract. If the contract requires requesting user 42 from a database dependency, record that boundary request and check its argument. Returning a canned row alone does not establish which request was made.
Assertions about private helpers can couple tests to structure. If an assertion names a private helper, renaming that helper may break the assertion even when public behaviour is preserved. Not every refactoring causes this. Check public results and contract-relevant boundary interactions where possible.
A mock configured to return a chosen network response can be used without asserting on recorded calls. In that test it supplies the stub role. Checking the final message may be enough for the stated contract. Merely naming an object a mock does not remove network access; the dependency must actually be replaced.
Control dependencies through a seam. Check public results and required boundary requests. A double does not test the real dependency.
Original lesson, questions and flashcards written for this learning dataset.
2 · Watch
به انگلیسیTake it off screen
Where it sits
Optional connections
This opens up
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.