В чем разница между интеграционным и модульным тестом?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Разница между интеграционным и модульным тестом
Модульные и интеграционные тесты — это два фундаментальных уровня тестирования, которые проверяют разные аспекты приложения и имеют разные цели, скорость исполнения и охват.
Определение
Модульный тест (Unit Test) проверяет отдельный компонент, функцию или модуль в изоляции от остального кода. Все зависимости заменяются моками или стабами.
Интеграционный тест (Integration Test) проверяет взаимодействие между несколькими модулями, компонентами или системами. Тесты работают с реальными или близкими к реальным зависимостями.
Основные различия
1. Область тестирования
Модульный тест проверяет одну функцию:
// utils.test.js
import { calculateTotal } from './utils';
test('calculateTotal должна суммировать цены с налогом', () => {
const result = calculateTotal([10, 20], 0.1); // 0.1 = 10% налог
expect(result).toBe(33); // (10+20) * 1.1
});
Интеграционный тест проверяет несколько компонентов вместе:
// ShoppingCart.integration.test.js
import { render, screen, fireEvent } from '@testing-library/react';
import ShoppingCart from './ShoppingCart';
import { CartProvider } from './CartContext';
test('добавление товара в корзину обновляет итоговую сумму', async () => {
render(
<CartProvider>
<ShoppingCart />
</CartProvider>
);
fireEvent.click(screen.getByText('Add Item'));
expect(screen.getByText(/Total: 33/)).toBeInTheDocument();
});
2. Использование моков
Модульный тест использует моки для всех зависимостей:
// UserService.test.js
import UserService from './UserService';
import * as API from './api';
jest.mock('./api');
test('getUserById должна вызвать API.fetch', async () => {
API.fetch.mockResolvedValue({ id: 1, name: 'John' });
const result = await UserService.getUserById(1);
expect(API.fetch).toHaveBeenCalledWith('/users/1');
expect(result.name).toBe('John');
});
Интеграционный тест использует реальные или тестовые реализации:
// UserService.integration.test.js
import UserService from './UserService';
import { mockServer } from './mocks/server'; // или реальный API
beforeAll(() => mockServer.listen());
test('getUserById должна получить реального пользователя', async () => {
mockServer.use(
http.get('/api/users/1', () =>
HttpResponse.json({ id: 1, name: 'John' })
)
);
const result = await UserService.getUserById(1);
expect(result.name).toBe('John');
});
3. Скорость исполнения
Модульные тесты очень быстрые (миллисекунды):
// Выполняется за 1-5ms
test('formatDate должна форматировать дату', () => {
expect(formatDate(new Date('2024-01-15'))).toBe('15.01.2024');
});
Интеграционные тесты медленнее (сотни миллисекунд или больше):
// Может выполняться 100-500ms из-за DOM манипуляций, API запросов
test('форма должна отправить данные и показать успех', async () => {
render(<RegistrationForm />);
// ... действия пользователя
// Ждем API ответа и DOM обновления
});
4. Цель и охват
| Аспект | Модульный | Интеграционный |
|---|---|---|
| Цель | Проверить логику функции | Проверить взаимодействие компонентов |
| Охват | Одна функция/компонент | Несколько компонентов/сервисов |
| Скорость | Очень быстро | Медленнее |
| Моки | Все зависимости | Минимум моков |
| Сложность | Проста написать | Сложнее, много настройки |
Практические примеры
Пример 1: Модульный тест
// calculator.test.js
import { add, multiply } from './calculator';
test('add(2, 3) должна вернуть 5', () => {
expect(add(2, 3)).toBe(5);
});
test('multiply(4, 5) должна вернуть 20', () => {
expect(multiply(4, 5)).toBe(20);
});
test('add должна работать с отрицательными числами', () => {
expect(add(-5, 3)).toBe(-2);
});
Пример 2: Интеграционный тест
// LoginFlow.integration.test.js
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import App from './App';
import { setupServer } from 'msw/node';
import { http, HttpResponse } from 'msw';
const server = setupServer(
http.post('/api/login', () =>
HttpResponse.json({ token: 'abc123', user: { id: 1, name: 'John' } })
)
);
beforeAll(() => server.listen());
aftTest(() => server.resetHandlers());
afterAll(() => server.close());
test('полный поток логина: ввод данных, отправка, редирект', async () => {
const user = userEvent.setup();
render(<App />);
// Ввод данных
await user.type(screen.getByLabelText(/email/i), 'user@example.com');
await user.type(screen.getByLabelText(/password/i), 'password123');
// Отправка формы
await user.click(screen.getByRole('button', { name: /login/i }));
// Ждем редиректа на главную
await waitFor(() => {
expect(screen.getByText('Welcome, John')).toBeInTheDocument();
});
});
Пример 3: Компонент с модульными тестами
// Button.test.js
import { render, screen, fireEvent } from '@testing-library/react';
import Button from './Button';
test('Button должна отрендериться с текстом', () => {
render(<Button>Click me</Button>);
expect(screen.getByText('Click me')).toBeInTheDocument();
});
test('Button должна вызвать onClick при клике', () => {
const handleClick = jest.fn();
render(<Button onClick={handleClick}>Click</Button>);
fireEvent.click(screen.getByText('Click'));
expect(handleClick).toHaveBeenCalledTimes(1);
});
test('Button должна быть отключена когда disabled=true', () => {
render(<Button disabled>Click</Button>);
expect(screen.getByText('Click')).toBeDisabled();
});
Когда использовать
Модульные тесты используются для:
- Отдельных функций-утилит
- Чистых функций (без побочных эффектов)
- Бизнес-логики
- Быстрой обратной связи при разработке
Интеграционные тесты используются для:
- Взаимодействия между компонентами
- Потоков пользователя (user flows)
- API интеграций
- Проверки, что все части работают вместе
Пирамида тестирования
/\
/E2E\
/______\
/ \
/ Integration\
/____________\
/ \
/ Unit Tests \
/________________\
Рекомендация: Много модульных тестов (быстро, дешево), умеренное количество интеграционных (проверяют взаимодействие), минимум E2E (медленно, дорого).
Вывод
Модульные и интеграционные тесты дополняют друг друга. Модульные тесты обеспечивают скорость и простоту, проверяя отдельные части. Интеграционные тесты проверяют, что все части работают вместе. Хорошая стратегия тестирования включает оба типа.