In JavaScript testing, mocking and spies are techniques used to observe or control function behavior without relying on real implementations. They help isolate units of code and verify interactions.

💡 What Are Mocks & Spies?
Mocks replace real functions or modules with controlled implementations, often returning predefined values.
Spies wrap real functions to record calls and arguments without changing behavior (though some frameworks allow spies to alter behavior).
Why Use Mocking & Spies?
- Isolate code from external dependencies (e.g., APIs, databases).
- Control function outputs to test edge cases.
- Verify that functions are called with expected arguments.
- Improve test reliability and speed.
Core Concepts
| Feature | Mock | Spy |
|---|---|---|
| Purpose | Replace function implementation | Observe function calls & arguments |
| Behavior | Fake behavior (custom return values) | Usually calls original function |
| Use Case | Isolate dependencies | Verify interactions |
| Modification | Yes | Optional |
Common APIs (Jest Example)
jest.fn()— Creates a mock function that can track calls and set return values.jest.spyOn(object, 'method')— Wraps an existing method to spy on it.mockFn.mockReturnValue(value)— Sets a fixed return value for a mock function.mockFn.mock.calls— Array of all calls to the mock function with arguments.mockFn.mockClear()— Resets call count and arguments.
💡 Note on Frameworks
Jest is widely used and provides built-in mocking & spying utilities. Other libraries like Sinon.js also offer rich mocking/spying features.
📌 Deep Dive: Mock Function Example
const fetchData = jest.fn();
fetchData.mockReturnValue(Promise.resolve('data'));
test('fetchData called and returns data', async () => {
const result = await fetchData();
expect(fetchData).toHaveBeenCalled();
expect(result).toBe('data');
});
📌 Deep Dive: Spy on Method Example
const calculator = {
add(a, b) {
return a + b;
}
};
test('spy on add method', () => {
const spy = jest.spyOn(calculator, 'add');
const result = calculator.add(2, 3);
expect(spy).toHaveBeenCalledWith(2, 3);
expect(result).toBe(5);
spy.mockRestore();
});
⚠️ Avoid Over-Mocking
Excessive mocking can lead to brittle tests that don't reflect real-world behavior. Mock only external dependencies, not the code under test.
Best Practices
- Mock external services, not your own functions unless needed.
- Use spies to confirm side effects or method invocations.
- Clear mocks/spies between tests to avoid state leaks.
- Prefer explicit mock return values to increase test clarity.
Quick Knowledge Check
Test what you just learned
Question 1 of 2
What is the primary purpose of a spy in testing?
Question 2 of 2
Which Jest function creates a mock function that can have its return value set?
Loading results...