← Назад к вопросам

В чем разница между интеграционным и модульным тестом?

2.0 Middle🔥 171 комментариев
#Архитектура и паттерны#Тестирование

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Разница между интеграционным и модульным тестом

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

Определение

Модульный тест (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 (медленно, дорого).

Вывод

Модульные и интеграционные тесты дополняют друг друга. Модульные тесты обеспечивают скорость и простоту, проверяя отдельные части. Интеграционные тесты проверяют, что все части работают вместе. Хорошая стратегия тестирования включает оба типа.

В чем разница между интеграционным и модульным тестом? | PrepBro