Unit-тесты сосредоточены на проверке отдельных компонентов или функций в изоляции. Они позволяют убедиться, что каждый элемент работает корректно, не зависимо от других частей приложения. В контексте React это чаще всего тестирование компонентов или вспомогательных функций, таких как утилиты для обработки данных или локальный стейт.
Integration-тесты проверяют взаимодействие нескольких компонентов и модулей между собой. Основная цель — убедиться, что система в целом ведёт себя ожидаемо, когда несколько частей соединяются. В React это может включать проверку работы формы с Redux или Context API, навигацию между страницами или корректное отображение компонентов при изменении пропсов и состояния.
| Характеристика | Unit-тест | Integration-тест |
|---|---|---|
| Фокус | Один компонент или функция | Взаимодействие нескольких компонентов |
| Зависимости | Минимальные, мокаются | Часто настоящие реализации, меньше моков |
| Скорость | Быстрее | Медленнее, так как рендерится больше компонентов |
| Применение React Testing Library | render с минимальным окружением, проверка отдельных
элементов и событий |
Полная отрисовка компонентов с дочерними элементами, проверка пользовательского сценария |
| Проверка состояния и эффекта | Локальный стейт, вызовы функций | Комбинация стейтов, контекста, эффектов |
Unit-тесты в React направлены на проверку:
Пример 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-тесты в React имитируют реальные сценарии использования приложения:
Пример интеграционного теста формы:
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-тест проверяет не только рендеринг, но и правильность логики, взаимодействия компонентов и глобального состояния.
Использовать screen для поиска
элементов Это делает тесты читаемыми и устойчивыми к изменениям
структуры JSX.
Отдавать предпочтение пользовательским сценариям Ищите элементы и взаимодействуйте с ними так, как это делает пользователь, а не через внутренние методы компонента.
Избегать чрезмерного мокирования в интеграционных тестах Моки полезны для unit-тестов, но интеграционные тесты должны максимально проверять реальные зависимости и взаимодействия.
Комбинировать тесты разных уровней Unit-тесты быстро выявляют ошибки в отдельных компонентах. Integration-тесты подтверждают, что части приложения корректно взаимодействуют.
Тестировать эффекты и состояние через действия пользователя Вместо проверки внутреннего состояния напрямую лучше проверять результат, который виден пользователю после действия.
Unit-тесты дают быстрый фидбек и локализуют ошибки, но не гарантируют корректность взаимодействия компонентов. Integration-тесты покрывают сценарии сложного взаимодействия, но выполняются медленнее. В React-приложении оптимально сочетать оба подхода: unit-тесты для изоляции логики, integration-тесты для проверки цепочек действий и пользовательских сценариев. Это обеспечивает надёжность приложения и упрощает сопровождение кода.