A mock is a test double for an outgoing dependency: something the code under test calls to produce an effect beyond itself. Instead of using the real logger, email service, module, or third-party system, a test supplies a controllable replacement and verifies the call and its arguments. This is interaction testing: proving that an important exit point was reached correctly. section 4.1 section 4.10
Mocks and stubs are easy to confuse because both replace dependencies. The distinction is the direction of information and what the test asserts. A stub supplies incoming data or behavior and is not verified. A mock represents an outgoing requirement and is verified. When the role is unclear, “test double” or “fake” is a safer general term. section 3.1 section 3.8
Verify a logger call
Inject a logger as a parameter, then use a small handwritten mock that records what it receives. After calling verifyPassword2, check the recorded text. The mock only needs the info method used by the code, while the production logger can have a larger interface. const mockLog = { info: (text) => { written = text; } }; verifyPassword2('anything', [], mockLog); expect(written).toMatch(/PASSED/); section 4.3
Listing 4.3 Handwritten mock object
describe('password verifier with logger', () => {
describe('when all rules pass', () => {
it('calls the logger with PASSED', () => {
let written = '';
const mockLog = {
info: (text) => {
written = text;
}
};
verifyPassword2('anything', [], mockLog);
expect(written).toMatch(/PASSED/);
});
});
});
A complete small test shows a mock recording a logger argument and verifying the observable interaction. section 4.3
Use mocks selectively to keep tests focused and trustworthy:
- Mock a third-party call when it is the meaningful outcome to prove, such as logging or sending an email. section 4.0
- Prefer return-value or state-based tests when they can prove the behavior; most tests need no mock. section 1.5 section 5.6.1
- Keep one mock per test in the usual case, because each mock represents a separate requirement. section 4.1
- Do not verify stubs or internal function calls; those checks couple a test to implementation details rather than an exit point. section 5.6.3 section 8.3.1
- Create mocks and their expectations near the test that uses them; use a helper when shared construction is needed. section 9.4
Interaction assertions can become fragile when they verify many incidental calls. A test with many expectations may fail after harmless implementation changes, obscure the scenario being tested, and leave later verifications unexecuted after an earlier failure. Verify only the interaction that expresses the current requirement, and split unrelated requirements into separate tests. section 4.4 section 5.6.5




















