We use cookies to enhance your experience on the site
CodeWorlds

Mocking in Jest

Mocking is creating artificial versions of functions, modules, or objects. In Jurassic Park, it is like creating dinosaur models for security tests instead of using real beasts.

jest.fn() - Creating Mock Functions

jest.fn()
creates an "empty" function that records all calls.

1test('jest.fn() - basics', () => {
2  // Creating a mock function
3  const feedDino = jest.fn();
4
5  // Calling the mock function
6  feedDino('Rex', 'meat');
7  feedDino('Brachio', 'plants');
8
9  // Checking calls
10  expect(feedDino).toHaveBeenCalled();
11  expect(feedDino).toHaveBeenCalledTimes(2);
12  expect(feedDino).toHaveBeenCalledWith('Rex', 'meat');
13  expect(feedDino).toHaveBeenLastCalledWith('Brachio', 'plants');
14});

Mock with Implementation

You can give a mock a behavior:

1test('mock with implementation', () => {
2  // Mock with return value
3  const getHealth = jest.fn().mockReturnValue(100);
4  expect(getHealth()).toBe(100);
5
6  // Mock with different values for subsequent calls
7  const checkSensor = jest.fn()
8    .mockReturnValueOnce('OK')
9    .mockReturnValueOnce('WARNING')
10    .mockReturnValueOnce('DANGER');
11
12  expect(checkSensor()).toBe('OK');
13  expect(checkSensor()).toBe('WARNING');
14  expect(checkSensor()).toBe('DANGER');
15
16  // Mock with custom implementation
17  const calculateDamage = jest.fn((attack, defense) => {
18    return Math.max(0, attack - defense);
19  });
20
21  expect(calculateDamage(50, 30)).toBe(20);
22  expect(calculateDamage(10, 30)).toBe(0);
23});

jest.mock() - Mocking Modules

jest.mock()
allows you to replace an entire module with a mock:

1// File: alertService.js
2export function sendAlert(zone, message) {
3  // In reality sends email/SMS - we don't want this in tests!
4  return fetch('/api/alerts', {
5    method: 'POST',
6    body: JSON.stringify({ zone, message })
7  });
8}
9
10// File: securitySystem.test.js
11jest.mock('./alertService');
12
13const { sendAlert } = require('./alertService');
14
15describe('SecuritySystem', () => {
16  beforeEach(() => {
17    // Reset mocks before each test
18    sendAlert.mockClear();
19    sendAlert.mockResolvedValue({ status: 'sent' });
20  });
21
22  it('should send alert on breach', async () => {
23    const system = new SecuritySystem();
24    await system.reportBreach('Zone A');
25
26    expect(sendAlert).toHaveBeenCalledWith(
27      'Zone A',
28      expect.stringContaining('breach')
29    );
30  });
31});

jest.spyOn() - Spying on Methods

spyOn
monitors an existing method without replacing it (by default).

1test('spyOn - monitoring a method', () => {
2  const park = {
3    dinosaurs: [],
4    addDinosaur(dino) {
5      this.dinosaurs.push(dino);
6      return this.dinosaurs.length;
7    },
8    getDinosaurCount() {
9      return this.dinosaurs.length;
10    }
11  };
12
13  // Spy on the method - preserves original implementation
14  const spy = jest.spyOn(park, 'addDinosaur');
15
16  park.addDinosaur({ name: 'Rex' });
17  park.addDinosaur({ name: 'Blue' });
18
19  // Check calls
20  expect(spy).toHaveBeenCalledTimes(2);
21  expect(spy).toHaveBeenCalledWith({ name: 'Rex' });
22
23  // The original function still works!
24  expect(park.dinosaurs).toHaveLength(2);
25
26  // Restore original implementation
27  spy.mockRestore();
28});

spyOn with Implementation Replacement

1test('spyOn - replacing implementation', () => {
2  const api = {
3    fetchDinoData(id) {
4      // Normal API call - we don't want this in tests
5      return fetch(`/api/dinosaurs/${id}`);
6    }
7  };
8
9  // Replace implementation for the duration of the test
10  const spy = jest.spyOn(api, 'fetchDinoData').mockImplementation((id) => {
11    return Promise.resolve({
12      id,
13      name: 'Mock Rex',
14      species: 'T-Rex'
15    });
16  });
17
18  // Now fetchDinoData returns mock data
19  api.fetchDinoData('001').then(data => {
20    expect(data.name).toBe('Mock Rex');
21  });
22
23  spy.mockRestore();
24});

Checking Mock Calls

Jest provides a rich set of matchers for mocks:

1test('matchers for mocks', () => {
2  const callback = jest.fn();
3
4  callback('Rex');
5  callback('Blue', 'raptor');
6
7  // Was it called?
8  expect(callback).toHaveBeenCalled();
9
10  // How many times?
11  expect(callback).toHaveBeenCalledTimes(2);
12
13  // With what arguments?
14  expect(callback).toHaveBeenCalledWith('Rex');
15  expect(callback).toHaveBeenNthCalledWith(1, 'Rex');
16  expect(callback).toHaveBeenNthCalledWith(2, 'Blue', 'raptor');
17
18  // Access to call details
19  expect(callback.mock.calls).toHaveLength(2);
20  expect(callback.mock.calls[0]).toEqual(['Rex']);
21  expect(callback.mock.calls[1]).toEqual(['Blue', 'raptor']);
22});
Go to CodeWorlds