Integration-testing vs unit-testing в контексте React

Unit-тесты сосредоточены на проверке отдельных компонентов или функций в изоляции. Они позволяют убедиться, что каждый элемент работает корректно, не зависимо от других частей приложения. В контексте React это чаще всего тестирование компонентов или вспомогательных функций, таких как утилиты для обработки данных или локальный стейт.

Integration-тесты проверяют взаимодействие нескольких компонентов и модулей между собой. Основная цель — убедиться, что система в целом ведёт себя ожидаемо, когда несколько частей соединяются. В React это может включать проверку работы формы с Redux или Context API, навигацию между страницами или корректное отображение компонентов при изменении пропсов и состояния.


Отличия подходов в React

Характеристика Unit-тест Integration-тест
Фокус Один компонент или функция Взаимодействие нескольких компонентов
Зависимости Минимальные, мокаются Часто настоящие реализации, меньше моков
Скорость Быстрее Медленнее, так как рендерится больше компонентов
Применение React Testing Library render с минимальным окружением, проверка отдельных элементов и событий Полная отрисовка компонентов с дочерними элементами, проверка пользовательского сценария
Проверка состояния и эффекта Локальный стейт, вызовы функций Комбинация стейтов, контекста, эффектов

Unit-тестирование компонентов

Unit-тесты в React направлены на проверку:

  • Отображения компонентов при различных пропсах.
  • Локального состояния и вызова функций обратного вызова.
  • Корректности рендера отдельных JSX-элементов.

Пример unit-теста для кнопки с callback:

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

test('вызывает onClick при нажатии', () => {
  const handleClick = jest.fn();
  render(<Button onCl ick={handleClick}>Нажми</Button>);

  fireEvent.click(screen.getByText('Нажми'));
  expect(handleClick).toHaveBeenCalledTimes(1);
});

Ключевое в unit-тесте — изоляция. Компонент тестируется отдельно, внешние зависимости подменяются мокаами.


Integration-тестирование компонентов

Integration-тесты в React имитируют реальные сценарии использования приложения:

  • Взаимодействие компонентов с контекстом, Redux или Router.
  • Проверка изменений состояния при выполнении действий пользователя.
  • Проверка цепочек событий и правильного рендера дочерних компонентов.

Пример интеграционного теста формы:

import { render, screen, fireEvent } from '@testing-library/react';
import { BrowserRouter } from 'react-router-dom';
import { Provider } from 'react-redux';
import store from './store';
import LoginForm from './LoginForm';

test('отправка формы обновляет состояние и перенаправляет', () => {
  render(
    <Provider store={store}>
      <BrowserRouter>
        <LoginForm />
      </BrowserRouter>
    </Provider>
  );

  fireEvent.change(screen.getByLabelText(/email/i), { target: { value: 'user@test.com' } });
  fireEvent.change(screen.getByLabelText(/password/i), { target: { value: '123456' } });
  fireEvent.click(screen.getByRole('button', { name: /войти/i }));

  expect(store.getState().auth.isAuthenticated).toBe(true);
  expect(window.location.pathname).toBe('/dashboard');
});

Integration-тест проверяет не только рендеринг, но и правильность логики, взаимодействия компонентов и глобального состояния.


Практические советы по React Testing Library

  1. Использовать screen для поиска элементов Это делает тесты читаемыми и устойчивыми к изменениям структуры JSX.

  2. Отдавать предпочтение пользовательским сценариям Ищите элементы и взаимодействуйте с ними так, как это делает пользователь, а не через внутренние методы компонента.

  3. Избегать чрезмерного мокирования в интеграционных тестах Моки полезны для unit-тестов, но интеграционные тесты должны максимально проверять реальные зависимости и взаимодействия.

  4. Комбинировать тесты разных уровней Unit-тесты быстро выявляют ошибки в отдельных компонентах. Integration-тесты подтверждают, что части приложения корректно взаимодействуют.

  5. Тестировать эффекты и состояние через действия пользователя Вместо проверки внутреннего состояния напрямую лучше проверять результат, который виден пользователю после действия.


Баланс между unit и integration-тестами

Unit-тесты дают быстрый фидбек и локализуют ошибки, но не гарантируют корректность взаимодействия компонентов. Integration-тесты покрывают сценарии сложного взаимодействия, но выполняются медленнее. В React-приложении оптимально сочетать оба подхода: unit-тесты для изоляции логики, integration-тесты для проверки цепочек действий и пользовательских сценариев. Это обеспечивает надёжность приложения и упрощает сопровождение кода.