Мокирование в тестировании — это процесс замены реальных зависимостей программы на их искусственные аналоги (моки), что позволяет тестировать отдельные компоненты или функции без взаимодействия с реальными внешними сервисами, базами данных или другими модулями. Jest предоставляет мощные инструменты для мокирования, которые можно использовать как для автоматического, так и для ручного мокирования зависимостей. Важно понять, когда и как применять оба подхода для эффективного тестирования.
Автоматическое мокирование — это процесс, при котором Jest сам
генерирует моки для импортируемых модулей. Это полезно, когда нужно
быстро заменить реальные зависимости, не заботясь о детальной настройке
мока. Jest имеет встроенную поддержку для автоматического мокирования
через функцию jest.mock().
Когда вызывается jest.mock(), Jest создает мок для
указанного модуля. Это позволяет вам тестировать компонент или функцию,
не затрагивая реальные реализации зависимостей. При этом Jest
автоматически заменяет все экспортируемые функции, возвращая моки вместо
настоящих функций.
Пример:
// file.js
export const fetchData = async () => {
const response = await fetch('https://api.example.com/data');
return response.json();
};
// file.test.js
jest.mock('./file');
test('fetchData returns mock data', async () => {
const mockData = { key: 'value' };
fetchData.mockResolvedValue(mockData);
const data = await fetchData();
expect(data).toEqual(mockData);
});
В этом примере Jest автоматически заменяет функцию
fetchData на мок, который возвращает заранее заданные
данные, избегая реального вызова API. Это позволяет изолировать
тестируемую логику и ускорить выполнение тестов.
jest.mock() весь модуль заменяется на мок, включая все его
функции и объекты.mockResolvedValue() и
mockRejectedValue().Ручное мокирование — это более гибкий подход, при котором вы самостоятельно создаете моки и задаете их поведение. Это полезно, если автоматическое мокирование не предоставляет нужной гибкости или контроля, например, когда необходимо контролировать поведение мока на более глубоком уровне.
Ручное мокирование предполагает создание мока с помощью
jest.fn(), который представляет собой фальшивую функцию с
настраиваемым поведением. Такой подход дает больше контроля над
тестируемыми зависимостями и позволяет моделировать их поведение с
высокой точностью.
Пример:
// file.js
export const fetchData = async (url) => {
const response = await fetch(url);
return response.json();
};
// file.test.js
const mockFetch = jest.fn();
jest.mock('fetch', () => mockFetch);
test('fetchData uses mockFetch', async () => {
const mockData = { key: 'value' };
mockFetch.mockResolvedValue({ json: () => mockData });
const data = await fetchData('https://api.example.com/data');
expect(mockFetch).toHaveBeenCalledWith('https://api.example.com/data');
expect(data).toEqual(mockData);
});
В этом примере создается собственный мок для функции
fetch, который настраивается с помощью
jest.fn(). Это дает возможность гибко настроить его
поведение и проверить, как именно используется эта зависимость в
коде.
jest.fn(): Для создания
мока используется jest.fn(), который представляет собой
фальшивую функцию, поддерживающую различные методы, такие как
mockReturnValue(), mockResolvedValue(),
mockRejectedValue(), а также позволяет следить за вызовами
с помощью mock.calls.| Характеристика | Автоматическое мокирование | Ручное мокирование |
|---|---|---|
| Уровень настройки | Ограниченная настройка, подход для простых случаев | Высокая гибкость, детальная настройка |
| Гибкость | Меньше гибкости, автоматически заменяет весь модуль | Полный контроль над поведением мока |
| Простота использования | Легко и быстро внедряется, подходит для большинства случаев | Требует больше кода, но дает точный контроль |
| Использование в тестах | Удобно для замены всего модуля или для простых зависимостей | Подходит для сложных случаев с контролем над поведением |
Автоматическое мокирование идеально подходит для простых сценариев, когда необходимо быстро заменить модули или функции, не углубляясь в детали их поведения. Это отличный выбор для тестирования кода, который зависит от множества внешних сервисов или утилит, и когда нужно минимизировать вмешательство в структуру теста.
Ручное мокирование следует использовать, когда необходимо больше контроля над тестируемыми зависимостями. Это полезно в случаях, когда нужно настроить поведение мока, имитируя различные сценарии работы с зависимостью, или когда автоматическое мокирование не подходит из-за сложности взаимодействия с внешними модулями.
// file.js
export const fetchData = async (url) => {
const response = await fetch(url);
const data = await response.json();
return data;
};
// file.test.js
const mockFetch = jest.fn();
global.fetch = mockFetch;
test('fetchData handles multiple responses correctly', async () => {
mockFetch.mockResolvedValueOnce({ json: () => ({ data: 'value1' }) });
mockFetch.mockResolvedValueOnce({ json: () => ({ data: 'value2' }) });
const data1 = await fetchData('https://api.example.com/1');
const data2 = await fetchData('https://api.example.com/2');
expect(data1).toEqual({ data: 'value1' });
expect(data2).toEqual({ data: 'value2' });
});
Здесь мы используем ручное мокирование для задания нескольких
различных ответов от функции fetch, что позволяет
протестировать работу с множественными источниками данных.
Мокирование — это неотъемлемая часть тестирования, позволяющая изолировать тестируемую логику от внешних зависимостей. Jest предоставляет два основных подхода к мокированию: автоматическое и ручное. Каждый из них имеет свои преимущества и ограничения, и выбор подхода зависит от сложности тестируемого кода и требований к контролю над зависимостями.