Тестирование контекста

Контексты в тестировании — важный аспект, обеспечивающий изоляцию и управление состоянием в тестах. В Jest контекст играет ключевую роль, когда требуется имитировать различные среды, сценарии или состояния в процессе тестирования функций, компонентов или модулей. Для работы с контекстом используется несколько методов, включая мокирование зависимостей, настройки глобальных объектов и использование контекстов в React. Понимание того, как правильно работать с контекстом, позволяет писать тесты, которые являются более точными и воспроизводимыми.

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

Мокирование (mocking) — это процесс замены реальных зависимостей фальшивыми объектами или функциями, что позволяет изолировать тестируемый код от внешних факторов. В Jest для мокирования контекста можно использовать функцию jest.mock(), которая заменяет модули или функции на моки.

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

// Модуль с функцией, которую нужно замокать
export const getUserInfo = () => {
  return fetch('/api/user')
    .then(response => response.json());
};

// Тест, где мы мокируем getUserInfo
import { getUserInfo } from './getUserInfo';
jest.mock('./getUserInfo');

test('должен вернуть данные пользователя', async () => {
  getUserInfo.mockResolvedValue({ name: 'Иван', age: 25 });

  const result = await getUserInfo();
  expect(result).toEqual({ name: 'Иван', age: 25 });
});

В этом примере мы заменили реальную функцию getUserInfo на мок, который возвращает заранее заданный результат. Это позволяет тестировать код, не выполняя реальный запрос к серверу.

Глобальные объекты и их настройка

Jest предоставляет возможность работы с глобальными объектами, такими как window, document, localStorage, что удобно при тестировании функционала, который зависит от них. Для их настройки можно использовать хуки, такие как beforeAll(), beforeEach(), afterAll(), afterEach().

Пример настройки глобальных объектов:

beforeAll(() => {
  global.localStorage = {
    getItem: jest.fn(),
    setItem: jest.fn(),
  };
});

test('проверка вызова localStorage', () => {
  localStorage.setItem('token', 'abc123');
  expect(localStorage.setItem).toHaveBeenCalledWith('token', 'abc123');
});

В этом примере мы заменили стандартный localStorage на мок, чтобы протестировать его использование без взаимодействия с реальным браузером.

Контекст в React и тестирование с использованием React Testing Library

React использует контексты для управления состоянием приложения, особенно когда нужно передавать данные через несколько уровней компонентов. Jest вместе с React Testing Library позволяет эффективно тестировать компоненты, использующие контекст.

Для тестирования компонентов с контекстом необходимо обернуть компонент в провайдер контекста и передать необходимые данные.

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

import { render, screen } from '@testing-library/react';
import { UserContext, UserProvider } from './UserContext';
import UserProfile from './UserProfile';

test('отображает информацию о пользователе', () => {
  const user = { name: 'Анна', age: 30 };

  render(
    <UserProvider value={user}>
      <UserProfile />
    </UserProvider>
  );

  expect(screen.getByText('Анна')).toBeInTheDocument();
  expect(screen.getByText('30')).toBeInTheDocument();
});

В этом примере мы используем провайдер контекста UserProvider для того, чтобы передать данные о пользователе в компонент UserProfile. Это позволяет тестировать компонент, не полагаясь на внешние зависимости.

Настройка контекста через jest.setup.js

Если необходимо выполнить настройку глобальных переменных или модулей перед всеми тестами, можно использовать файл jest.setup.js. В этом файле можно определить, какие глобальные объекты будут доступны в тестах, или настроить поведение некоторых библиотек.

Пример настройки через jest.setup.js:

// jest.setup.js
global.fetch = jest.fn(() =>
  Promise.resolve({
    json: () => Promise.resolve({ name: 'Иван', age: 25 }),
  })
);

Этот файл будет выполнен до начала всех тестов, что позволяет избежать дублирования настройки в каждом тесте.

Имитация контекста с использованием jest.spyOn()

Для тестирования функций, которые зависят от контекста или состояния, можно использовать метод jest.spyOn(). Он позволяет создать шпион на методах объектов и проверять, как они были вызваны.

Пример использования jest.spyOn():

import { getUserInfo } from './userApi';

test('проверка вызова getUserInfo', () => {
  const spy = jest.spyOn(global, 'fetch');
  spy.mockResolvedValue({
    json: jest.fn().mockResolvedValue({ name: 'Иван' }),
  });

  getUserInfo();

  expect(spy).toHaveBeenCalledWith('/api/user');
  spy.mockRestore();
});

Здесь мы используем jest.spyOn() для шпионажа на глобальном методе fetch, проверяя, что он был вызван с нужным аргументом.

Работа с асинхронными тестами и контекстом

Контекст может также включать асинхронные операции, например, запросы к серверу. В таких случаях важно правильно настроить тесты, чтобы они ожидали завершения асинхронных операций. Jest предоставляет несколько способов работы с асинхронностью, включая async/await, done и возвращение промисов.

Пример асинхронного теста:

test('асинхронный запрос данных', async () => {
  const data = await fetchDataFromApi();

  expect(data).toEqual({ name: 'Иван', age: 30 });
});

Когда тест зависит от асинхронных операций, важно дождаться завершения этих операций перед проверкой результатов.

Мокирование контекста и интеграционные тесты

Для более сложных тестов, которые включают интеграцию нескольких частей системы, часто необходимо замокировать контекст на более высоком уровне. Это помогает изолировать тестируемую часть и предотвратить непредсказуемые побочные эффекты от других частей системы.

Пример интеграционного теста с мокированием контекста:

import { render, screen } from '@testing-library/react';
import { MyComponent } from './MyComponent';
import { UserContext } from './UserContext';

jest.mock('./UserContext', () => ({
  ...jest.requireActual('./UserContext'),
  useUser: jest.fn(),
}));

test('интеграционный тест с мокированным контекстом', () => {
  const mockUser = { name: 'Анна', age: 25 };
  useUser.mockReturnValue(mockUser);

  render(<MyComponent />);

  expect(screen.getByText('Анна')).toBeInTheDocument();
  expect(screen.getByText('25')).toBeInTheDocument();
});

В данном примере мы мокируем хук useUser, который используется в компоненте MyComponent, и проверяем, что компонент корректно отображает данные, полученные из контекста.

Заключение

Тестирование контекста в Jest играет важную роль в создании стабильных и изолированных тестов. Использование моков, настройка глобальных объектов и правильное использование контекстов в React позволяют создавать надежные тесты, которые отражают реальное поведение приложения. Знание различных техник работы с контекстом помогает повысить качество тестирования, улучшить поддержку кода и ускорить процесс разработки.