Мокирование библиотек

Мокирование внешних зависимостей является неотъемлемой частью юнит-тестирования в JavaScript, в том числе при использовании Enzyme для тестирования компонентов React. Мокирование позволяет имитировать поведение зависимостей, чтобы сосредоточиться на тестировании компонента, а не на внешних библиотеках или API. В этой части рассмотрим, как правильно мокировать библиотеки в тестах с использованием Enzyme, а также основные подходы и инструменты для эффективного мокирования.

Что такое мокирование и зачем оно нужно?

Мокирование — это процесс создания поддельных версий внешних зависимостей, которые имитируют их поведение. Это позволяет тестировать компонент в изоляции, не полагаясь на реальное поведение сложных зависимостей, таких как API-запросы, сторонние библиотеки или даже собственные модули, которые трудно или невозможно протестировать напрямую.

Мокирование помогает:

  • Изолировать тестируемый компонент от внешних изменений.
  • Протестировать поведение компонента в различных сценариях, например, с ошибками от API или специфическими данными.
  • Повысить скорость тестов, избегая обращения к реальным внешним сервисам.

Основные способы мокирования

В экосистеме JavaScript существует несколько подходов к мокированию зависимостей. Основные из них:

  1. Мокирование с помощью Jest — наиболее популярный инструмент для мокирования в тестах React.
  2. Мокирование с помощью Sinon — предоставляет более гибкие возможности для работы с шпионами и мокающими функциями.
  3. Мокирование с использованием Enzyme — Enzyme предоставляет возможности для тестирования компонентов, взаимодействующих с внешними зависимостями.

Мокирование внешних библиотек с Jest

Jest предлагает встроенные функции для мокирования модулей и зависимостей, такие как jest.mock(), jest.fn() и jest.spyOn(). Это позволяет создавать простые и гибкие моки для любых зависимостей.

Пример мокирования библиотеки

Для начала рассмотрим пример, когда компонент зависит от внешней библиотеки, например, axios для выполнения HTTP-запросов.

import React from 'react';
import { shallow } from 'enzyme';
import axios from 'axios';
import MyComponent from './MyComponent';

jest.mock('axios'); // Мокируем axios

describe('MyComponent', () => {
  it('должен загрузить данные при монтировании', async () => {
    const data = { response: 'success' };
    axios.get.mockResolvedValue({ data }); // Мокируем успешный ответ

    const wrapper = shallow(<MyComponent />);
    await wrapper.instance().componentDidMount(); // Запуск компонента

    expect(wrapper.state().data).toEqual(data);
  });
});

В данном примере библиотека axios мокируется с помощью jest.mock(), после чего мы задаем ожидаемое поведение с помощью mockResolvedValue(). Это позволяет тестировать компонент, не выполняя реальных HTTP-запросов.

Мокирование функций

Иногда необходимо мокировать не целые библиотеки, а только их отдельные функции. В этом случае можно использовать jest.fn(). Этот метод позволяет создать поддельную версию функции с возможностью отслеживания её вызовов и возвращаемых значений.

Пример мокирования функции

import React from 'react';
import { shallow } from 'enzyme';
import MyComponent from './MyComponent';

describe('MyComponent', () => {
  it('должен вызывать функцию при клике', () => {
    const mockFunction = jest.fn(); // Создаем поддельную функцию
    const wrapper = shallow(<MyComponent onCl ick={mockFunction} />);
    
    wrapper.find('button').simulate('click'); // Симулируем клик

    expect(mockFunction).toHaveBeenCalledTimes(1); // Проверяем, что функция вызвана один раз
  });
});

В этом примере используется jest.fn() для мокирования функции, передаваемой в компонент через пропсы. При клике на кнопку вызывается мокированная функция, и затем проверяется, что она была вызвана.

Мокирование библиотек с Sinon

Sinon — это мощная библиотека для мокирования, шпионства и создания заглушек в JavaScript. Она может быть полезна, когда требуется больше контроля над поведением мока, например, для проверки вызовов функций или замены реальных методов.

Пример мокирования с Sinon

import React from 'react';
import { shallow } from 'enzyme';
import sinon from 'sinon';
import MyComponent from './MyComponent';

describe('MyComponent', () => {
  it('должен вызывать функцию onClick', () => {
    const onCl ick = sinon.spy(); // Создаем шпиона

    const wrapper = shallow(<MyComponent onCl ick={onClick} />);
    wrapper.find('button').simulate('click'); // Симулируем клик

    expect(onClick.calledOnce).toBe(true); // Проверяем, что функция была вызвана один раз
  });
});

Здесь мы использовали sinon.spy() для создания шпиона, который отслеживает вызовы функции. После клика по кнопке проверяется, что функция была вызвана.

Мокирование асинхронных операций

Мокирование асинхронных операций, таких как HTTP-запросы или запросы к базе данных, также играет важную роль в тестировании компонентов. Обычно для этого используется jest.mock() с асинхронными методами, такими как mockResolvedValue() или mockRejectedValue().

Пример мокирования асинхронных операций

import React from 'react';
import { shallow } from 'enzyme';
import axios from 'axios';
import MyComponent from './MyComponent';

jest.mock('axios'); // Мокируем axios

describe('MyComponent', () => {
  it('должен обработать ошибку при неудачном запросе', async () => {
    axios.get.mockRejectedValue(new Error('Ошибка сети')); // Мокируем ошибку

    const wrapper = shallow(<MyComponent />);
    await wrapper.instance().componentDidMount(); // Запуск компонента

    expect(wrapper.state().error).toBe('Ошибка сети'); // Проверяем, что ошибка обработана
  });
});

В этом примере мы мокируем ошибку, возникающую при запросе с помощью mockRejectedValue(). Это позволяет убедиться, что компонент правильно обрабатывает ошибки.

Мокирование с Enzyme

Enzyme предоставляет возможности для мокирования, хотя чаще всего это осуществляется с помощью Jest или Sinon в связке с Enzyme. Однако сам Enzyme предоставляет методы для работы с состоянием компонента, его методами и жизненным циклом, что важно при тестировании мокированных компонентов.

Пример мокирования компонента в Enzyme

import React from 'react';
import { shallow } from 'enzyme';
import MyComponent from './MyComponent';

describe('MyComponent', () => {
  it('должен вызвать метод после монтирования', () => {
    const mockMethod = jest.fn();
    const wrapper = shallow(<MyComponent />);
    
    wrapper.instance().someMethod = mockMethod; // Заменяем метод на мок
    wrapper.instance().componentDidMount(); // Вызываем жизненный цикл

    expect(mockMethod).toHaveBeenCalled(); // Проверяем вызов мока
  });
});

Здесь происходит мокирование метода компонента, чтобы проверить его вызов в процессе жизненного цикла компонента.

Заключение

Мокирование внешних зависимостей в Enzyme и Jest помогает изолировать тестируемый компонент, улучшить тестируемость и повысить скорость тестов. Для мокирования можно использовать различные подходы, включая встроенные функции Jest (jest.mock(), jest.fn(), mockResolvedValue()), а также сторонние библиотеки, такие как Sinon. Важно помнить, что мокирование должно быть использовано разумно, чтобы не создавать излишнюю сложность в тестах, а лишь повысить их стабильность и предсказуемость.