React ~ Testing ~ Mocking Functions - rohit120582sharma/Documentation GitHub Wiki
Mocking in Jest is about replacing dependencies with the Mock Function.
The Mock Function provides features to:
- Capture calls
- Set return values
- Change the implementation or promise resolution
There are three main types of module and function mocking in Jest:
- jest.spyOn: Spy or mock a function
- jest.fn: Mock a function
- jest.mock: Mock a module
Sometimes you only want to watch a method be called, but keep the original implementation:
import * as app from './app';
import * as math from './math';
test('calls math.add', () => {
const addMock = jest.spyOn(math, 'add');
// calls the original implementation
expect(app.doAdd(1, 2)).toEqual(3);
// and the spy stores the calls to add
expect(addMock).toHaveBeenCalledWith(1, 2);
});
In other cases, you may want to mock a function (it's implementation), but then restore the original implementation later in the suite:
import * as app from './app';
import * as math from './math';
test('calls math.add', () => {
const addMock = jest.spyOn(math, 'add');
// Override the implementation
addMock.mockImplementation(() => 'mock');
expect(app.doAdd(1, 2)).toEqual('mock');
// Restore the original implementation
addMock.mockRestore();
expect(app.doAdd(1, 2)).toEqual(3);
});
The most basic strategy for mocking is to reassign a function to the Mock Function. Then, anywhere the reassigned functions are used, the mock will be called instead of the original function:
One of the chances to use the Mock Function is that when your code supports dependency injection.
import * as app from './app';
import * as math from './math';
math.add = jest.fn();
math.subtract = jest.fn((a, b) => (a - b)); // with mock implementation
test('calls math.add', () => {
app.doAdd(1, 2);
expect(math.add).toHaveBeenCalledWith(1, 2);
});
test('calls math.subtract', () => {
app.doSubtract(1, 2);
expect(math.subtract).toHaveBeenCalledWith(1, 2);
});
A more common approach is to use jest.mock to automatically set all exports of a module to the Mock Function. The only disadvantage of this strategy is that it’s difficult to access the original implementation of the module.
import * as app from './app';
import * as math from './math';
// Set all module functions to jest.fn
jest.mock('./math.js', () => {
const actualMath = require.requireActual('./math');
return {
...actualMath,
add: (a, b) => a + b,
subtract: (a, b) => a - b
};
});
beforeEach(() => {
// Clear the mock data
math.add.mockClear();
math.subtract.mockClear();
});
test('should call math.add only onetime', () => {
app.doAdd(1, 2);
expect(math.add).toHaveBeenCalledTimes(1);
});
test('should call math.add with right arguments', () => {
app.doAdd(1, 2);
expect(math.add).toHaveBeenCalledWith(1, 2);
});
test('should call math.subtract only onetime', () => {
app.doSubtract(1, 2);
expect(math.add).toHaveBeenCalledTimes(1);
});
test('should calls math.subtract with right arguments', () => {
app.doSubtract(1, 2);
expect(math.subtract).toHaveBeenCalledWith(1, 2);
});