Testing JavaScript
Mocking — Functions, Modules, Timers
Master mocking in Jest. Learn to mock callback functions (jest.fn), mock entire modules (jest.mock), and control time execution dynamically.
1. Introduction
Mocking is a testing technique used to isolate the code under test by replacing real dependencies (like network modules, third-party libraries, or timer functions) with simulated implementations.
2. Why It Matters
Unit tests must be fast and deterministic. If a function queries a database or calls a third-party billing API, executing the real calls inside tests is slow, requires network access, and can result in actual charges or state changes. Mocking replaces these API wrappers with simulated implementations, allowing you to test your business logic in isolation.
3. Real-World Analogy
Think of a Crash Test Dummy (Mock):
- Real Dependency (Human driver): Putting a real person inside a car to test the airbags is dangerous and unethical.
- Mock (Crash Test Dummy): You place a sensor-equipped dummy in the seat. The dummy matches a human shape and weight, but is expendable. The sensors record data during the crash, allowing you to test the safety features safely.
4. Mocking Functions with jest.fn()
jest.fn() creates a mock function. You can use it to track callbacks: check if they were called, how many times, and with what arguments:
5. Mocking Modules with jest.mock()
To intercept imports of entire modules (like axios or database drivers), use jest.mock():
6. Mocking Timers
Testing functions that wait (like debounces or animations) would normally require delaying the test suite. Jest allows you to use fake timers, controlling execution time programmatically:
7. Common Mistakes
- Leaking mock state across tests: Mock functions retain execution records (like call counts or parameters) across tests. If you don't clear mock history, assertions inside sibling tests can fail. Clear mock history inside
beforeEachblocks usingjest.clearAllMocks().
8. Quick Quiz
Q1: Which Jest command allows you to speed up slow timeout tests by controlling the clock programmatically?
A) jest.mock('timer')
B) jest.useFakeTimers()
Answer: B — jest.useFakeTimers() mock system timers, allowing you to advance time programmatically without waiting.
9. Scenario-Based Challenge
The Dynamic Stripe API Billing Mock:
A payment helper calls: stripe.charge(userId, amount). Running actual payments during tests is dangerous. Write a Jest test suite that mock the stripe module dependency using jest.mock, asserting that the charge function is called with the correct parameters without executing the payment.
10. Debugging Exercise
Explain why this test fails to run or throws an assertion error, and how to fix it:
const myMock = jest.fn();test('test A', () => { myMock(); expect(myMock).toHaveBeenCalledTimes(1); // Passes! });
test('test B', () => { myMock(); // Bug: call count is aggregated from Test A! expect(myMock).toHaveBeenCalledTimes(1); // Fails! expected 1, received 2. Why? });
View Solution
Diagnosis: The mock function myMock is declared in the outer scope, retaining its call history across tests. The call in Test A is carried over, causing Test B to fail with a call count of 2.
Fix: Clear mock history between tests inside a beforeEach block, or re-instantiate the mock inside each test:
beforeEach(() => {
jest.clearAllMocks(); // Resets call counts and parameters!
});
11. Interview Questions
🟢 Q1: Explain the difference between mock, spy, and stub.
Answer: These terms represent different types of test doubles:
• Stub: A mock that provides canned responses to queries (e.g. returning static database records) to satisfy dependencies.
• Mock: A mock that focuses on verifying behavior (e.g. asserting that a specific function was called with the correct parameters).
• Spy: A wrapper that monitors a real object's methods. Unlike a mock, a spy delegates calls to the real implementation, recording invocation logs without replacing the original behavior (e.g. jest.spyOn(console, 'log')).
12. Production Considerations
- • Mock Cleanups: Set the configuration property
"clearMocks": trueinside yourjest.config.jsfile to clear mock history automatically between tests, preventing state pollution.