Jest: моки (jest.fn, jest.mock)

jest.fn создаёт mock-функцию с отслеживанием вызовов, а jest.mock полностью заменяет модуль на автоматический или ручной mock — основа изоляции unit-тестов.

Зачем нужно

Mock позволяет изолировать тестируемый код от внешних зависимостей: HTTP-запросов, базы данных, файловой системы. Тест становится быстрым, предсказуемым и не зависит от окружения. Без моков unit-тест превращается в integration-тест.

Где используется

  • Замена API-клиентов (axios, fetch) в unit-тестах
  • Изоляция сервисов друг от друга в модульных тестах
  • Контроль возвращаемых значений для тестирования разных сценариев
  • Проверка, что зависимость была вызвана с нужными аргументами

Основной контент

jest.fn — mock-функция

const mockCallback = jest.fn;

// Задать возвращаемое значение
mockCallback.mockReturnValue(42);
mockCallback.mockReturnValueOnce('first call').mockReturnValueOnce('second');

// Задать реализацию
mockCallback.mockImplementation((x) => x * 2);

// Задать Promise
mockCallback.mockResolvedValue({ data:  });
mockCallback.mockRejectedValue(new Error('Network error'));

// Проверки
expect(mockCallback).toHaveBeenCalled();
expect(mockCallback).toHaveBeenCalledTimes(2);
expect(mockCallback).toHaveBeenCalledWith('arg1', 'arg2');

jest.mock — мокирование модуля

// __mocks__/axios.js НЕ нужен — jest.mock заменяет автоматически
jest.mock('axios');

import axios from 'axios';
import { getUser } from './userService';

test('получает пользователя', async () => {
  axios.get.mockResolvedValue({ data: { id: 1, name: 'Alice' } });

  const user = await getUser(1);

  expect(axios.get).toHaveBeenCalledWith('/api/users/1');
  expect(user.name).toBe('Alice');
});

Частичный мок модуля

jest.mock('./utils', () => ({
  ...jest.requireActual('./utils'), // оставляем реальные методы
  formatDate: jest.fn( => '01.01.2024'), // мокируем только этот
}));

Ручной mock (mocks)

src/
  services/
    api.js
  __mocks__/
    api.js  ← ручной mock
// __mocks__/api.js
module.exports = {
  getUser: jest.fn.mockResolvedValue({ id: 1, name: 'Mock User' }),
};
// В тесте
jest.mock('./services/api'); // Jest подхватит __mocks__/api.js

Сброс и очистка моков

afterEach(() => {
  jest.clearAllMocks;   // сбрасывает историю вызовов
  // jest.resetAllMocks — сбрасывает историю + реализацию
  // jest.restoreAllMocks — восстанавливает spyOn оригиналы
});

Частые ошибки

  • jest.mock не в верхнем уровне файла — Jest поднимает jest.mock вверх (hoisting), но если написать внутри функции, поведение непредсказуемо
  • Забытый clearAllMocks — моки накапливают историю между тестами и ломают toHaveBeenCalledTimes
  • Мок без mockResolvedValue для async — если mock-функция не возвращает Promise, await вернёт undefined
  • Мокирование defaultExport ES-модуля — нужен { default: mockFn } или __esModule: true

Связанные темы

Ресурсы