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

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

1.0 Junior🔥 171 комментариев
#Тестирование

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

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

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

Unit vs Модульное vs Интеграционное тестирование

Эти три типа тестирования образуют пирамиду тестов (Test Pyramid) и работают на разных уровнях абстракции приложения.

Unit тестирование

Unit тест — это тест отдельной функции, метода или класса в изоляции. Проверяет одну единицу функциональности.

Характеристики:

  • Тестирует одну функцию/метод
  • Использует моки для зависимостей
  • Быстрое выполнение (миллисекунды)
  • Должно быть большое количество
import pytest
from unittest.mock import Mock

class Calculator:
    def __init__(self, logger):
        self.logger = logger
    
    def add(self, a: int, b: int) -> int:
        result = a + b
        self.logger.log(f"Added {a} + {b} = {result}")
        return result

def test_calculator_add():
    # Мокируем зависимость
    mock_logger = Mock()
    calc = Calculator(mock_logger)
    
    # Тестируем только функцию add
    result = calc.add(2, 3)
    
    assert result == 5
    mock_logger.log.assert_called_once()

Модульное тестирование (Module testing)

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

Характеристики:

  • Тестирует несколько взаимосвязанных функций
  • Может использовать реальные объекты (не всегда моки)
  • Проверяет взаимодействие компонентов в модуле
  • Медленнее unit тестов, но быстрее интеграционных
class UserRepository:
    def __init__(self, db):
        self.db = db
    
    def create(self, name: str, email: str) -> int:
        return self.db.insert("users", {"name": name, "email": email})
    
    def get_by_email(self, email: str) -> dict:
        return self.db.query("SELECT * FROM users WHERE email = %s", email)

class UserService:
    def __init__(self, repository):
        self.repository = repository
    
    def register_user(self, name: str, email: str) -> int:
        existing = self.repository.get_by_email(email)
        if existing:
            raise ValueError("User already exists")
        return self.repository.create(name, email)

def test_user_registration():
    # Используем реальный репозиторий, но с mock БД
    mock_db = Mock()
    mock_db.query.return_value = None  # Пользователь не существует
    mock_db.insert.return_value = 1
    
    repo = UserRepository(mock_db)
    service = UserService(repo)
    
    # Проверяем взаимодействие UserService и UserRepository
    user_id = service.register_user("John", "john@example.com")
    assert user_id == 1
    mock_db.insert.assert_called_once()

Интеграционное тестирование

Интеграционный тест проверяет, как разные модули/компоненты работают вместе. Использует реальные зависимости (БД, API, файловая система).

Характеристики:

  • Тестирует несколько модулей вместе
  • Использует реальные зависимости (БД, сеть)
  • Медленное выполнение (секунды)
  • Должно быть меньше, чем unit тестов
import pytest
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

# Используем реальную БД (обычно тестовую)
engine = create_engine("sqlite:///:memory:")
Session = sessionmaker(bind=engine)

def test_user_registration_integration():
    # Реальная БД
    db = Session()
    repo = UserRepository(db)
    service = UserService(repo)
    
    # Проверяем полный процесс
    user_id = service.register_user("John", "john@example.com")
    assert user_id > 0
    
    # Проверяем, что данные реально в БД
    user = repo.get_by_email("john@example.com")
    assert user["name"] == "John"

Пирамида тестов

       /\
      /  \  E2E / API тесты (мало, медленно)
     /----\
    /      \  Интеграционные тесты (среднее количество)
   /--------\
  /          \  Unit тесты (много, быстро)
 /____________\

Сравнительная таблица

КритерийUnitМодульноеИнтеграционное
Область тестированияОдна функцияНесколько функцийНесколько модулей
ЗависимостиМокиМоки/реальныеРеальные
СкоростьБыстро (мс)Средне (мс-сек)Медленно (сек)
СложностьПростаяСредняяСложная
КоличествоМного (70-80%)Среднее (10-15%)Мало (10-15%)
ИзоляцияПолнаяЧастичнаяМинимальная
ОтладкаЛегкоСреднеСложно

Пример с разными уровнями

class PaymentService:
    def __init__(self, gateway, db):
        self.gateway = gateway  # Платёжный шлюз (Stripe, PayPal)
        self.db = db
    
    def process_payment(self, user_id: int, amount: float) -> bool:
        transaction_id = self.gateway.charge(amount)
        self.db.save_transaction(user_id, transaction_id, amount)
        return True

# Unit тест - мокируем всё
def test_process_payment_unit():
    mock_gateway = Mock()
    mock_gateway.charge.return_value = "txn_123"
    mock_db = Mock()
    
    service = PaymentService(mock_gateway, mock_db)
    result = service.process_payment(1, 100.0)
    
    assert result is True
    mock_gateway.charge.assert_called_once_with(100.0)

# Интеграционный тест - реальная БД и мок шлюза
def test_process_payment_integration():
    real_db = Session()  # Реальная БД
    mock_gateway = Mock()
    mock_gateway.charge.return_value = "txn_123"
    
    service = PaymentService(mock_gateway, real_db)
    result = service.process_payment(1, 100.0)
    
    assert result is True
    # Проверяем, что транзакция реально в БД
    transaction = real_db.query(Transaction).filter_by(
        id="txn_123"
    ).first()
    assert transaction is not None

Когда использовать каждый тип

Unit тесты:

  • Для критической бизнес-логики
  • Для функций с множеством путей выполнения
  • Для функций, которые сложно тестировать интеграционно

Модульные тесты:

  • Для проверки взаимодействия компонентов модуля
  • Для сложной логики, объединяющей несколько функций

Интеграционные тесты:

  • Для API endpoints
  • Для проверки работы с БД
  • Для workflow, задействующих несколько сервисов

Рекомендация: соблюдайте пирамиду тестов — много unit тестов, среднее количество модульных, мало интеграционных.