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

Как называются тесты с mock?

2.2 Middle🔥 201 комментариев
#Тестирование

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

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

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

Типы тестов с Mock объектами

Тесты, использующие mock объекты, имеют специальную терминологию и классификацию в зависимости от уровня и подхода.

Unit Tests (Модульные тесты)

Основной тип тестов с mock. Тестируют одну функцию/метод в изоляции:

import unittest
from unittest.mock import Mock, patch

class PaymentService:
    def __init__(self, gateway):
        self.gateway = gateway
    
    def process_payment(self, amount):
        return self.gateway.charge(amount)

class TestPaymentService(unittest.TestCase):
    def test_process_payment(self):
        # Mock объект вместо реального gateway
        mock_gateway = Mock()
        mock_gateway.charge.return_value = True
        
        service = PaymentService(mock_gateway)
        result = service.process_payment(100)
        
        self.assertTrue(result)
        mock_gateway.charge.assert_called_once_with(100)

Test Doubles — общее название для всех подменяемых объектов

Это группа тестовых техник:

  1. Mock — проверяет взаимодействие (был ли вызван метод)
  2. Stub — возвращает заранее подготовленные данные
  3. Fake — рабочая реализация для тестирования
  4. Spy — отслеживает вызовы реального объекта
  5. Dummy — пустой объект для заполнения параметров
# Stub — возвращает фиксированное значение
stub_user = Mock()
stub_user.get_age.return_value = 25

# Dummy — просто заполняет параметр
dummy_logger = Mock()
service = MyService(dummy_logger)  # logger не используется

# Spy — отслеживает реальный объект
with patch('module.real_function') as spy:
    spy.side_effect = lambda x: x * 2
    result = spy(5)
    spy.assert_called_once_with(5)

Isolation Tests (Тесты изоляции)

Тесты, полностью изолирующие код от зависимостей:

from unittest.mock import patch

class UserRepository:
    def get_user(self, user_id):
        # Реальный запрос в БД
        pass

class UserService:
    def __init__(self, repo):
        self.repo = repo
    
    def get_user_age(self, user_id):
        user = self.repo.get_user(user_id)
        return user['age']

def test_user_service():
    # Изолируем от БД
    mock_repo = Mock()
    mock_repo.get_user.return_value = {'name': 'Alice', 'age': 30}
    
    service = UserService(mock_repo)
    age = service.get_user_age(1)
    
    assert age == 30
    mock_repo.get_user.assert_called_once_with(1)

State-based Testing vs Behavior-based Testing

State-based (Mock as Stub):

  • Проверяет изменение состояния после вызова
  • Фокус на результате
def test_increment_state():
    counter = Counter()
    counter.increment()
    assert counter.value == 1  # Проверяем состояние

Behavior-based (Mock assertions):

  • Проверяет, были ли вызваны методы и с какими аргументами
  • Фокус на взаимодействии
def test_increment_behavior():
    mock_observer = Mock()
    counter = Counter(mock_observer)
    counter.increment()
    
    # Проверяем вызов
    mock_observer.on_increment.assert_called_once()

Integration Tests с частичным mocking

Тесты, которые тестируют взаимодействие нескольких компонентов:

class TestOrderService(unittest.TestCase):
    @patch('services.payment_gateway')
    def test_create_order(self, mock_payment):
        # Мокируем только payment gateway
        # Остальное работает реально
        mock_payment.charge.return_value = True
        
        order_service = OrderService()
        order = order_service.create_order(items=[...])
        
        assert order.status == 'paid'
        mock_payment.charge.assert_called_once()

Parameterized Tests с Mock

Тесты с разными параметрами для одной функции:

import pytest
from unittest.mock import Mock

class TestValidator:
    @pytest.mark.parametrize('input,expected', [
        ('abc', True),
        ('123', False),
        ('', False),
    ])
    def test_validate_string(self, input, expected):
        mock_logger = Mock()
        validator = Validator(mock_logger)
        result = validator.is_valid(input)
        assert result == expected

Snapshot Tests с Mock

Тесты, проверяющие неизменяемость поведения:

import pytest
from unittest.mock import Mock

def test_api_response_snapshot(snapshot):
    mock_api = Mock()
    mock_api.get_users.return_value = [
        {'id': 1, 'name': 'Alice'},
        {'id': 2, 'name': 'Bob'},
    ]
    
    # Проверяем, что ответ соответствует сохранённому
    snapshot.assert_match(mock_api.get_users())

Contract Tests

Тесты, проверяющие контракт между компонентами:

from unittest.mock import Mock, call

def test_payment_contract():
    # Контракт: payment gateway должен быть вызван определённым образом
    mock_gateway = Mock(spec=['charge', 'refund'])
    
    service = PaymentService(mock_gateway)
    service.process_payment(100)
    service.refund_payment(100)
    
    # Проверяем контракт
    expected_calls = [call.charge(100), call.refund(100)]
    assert mock_gateway.method_calls == expected_calls

Mutation Tests

Тесты, проверяющие качество других тестов (мутируют код и смотрят, упадут ли тесты):

# Используют инструменты типа mutmut, cosmic-ray
# Проверяют, что тесты действительно ловят баги

Golden Master Tests

Тесты, проверяющие, что вывод соответствует эталонному:

def test_report_generation():
    mock_data = Mock()
    mock_data.get_records.return_value = [...]
    
    report = generate_report(mock_data)
    
    # Сравниваем с эталонным отчётом
    assert report == golden_master_report

Практические рекомендации

Когда использовать Mock:

  • Тестирование внешних зависимостей (API, БД, файловая система)
  • Изолирование бизнес-логики для быстрых unit тестов
  • Проверка взаимодействия между компонентами

Когда избегать Mock:

  • Не мокируй то, что быстро работает (обычные классы)
  • Не создавай сложные моки — это признак плохого дизайна
  • Используй реальные объекты для интеграционных тестов

Best Practices:

  • Мокируй только необходимые зависимости
  • Используй Mock для проверки вызовов, Stub для подготовки данных
  • Не переусложняй моки — они должны быть понятны
  • Комбинируй unit тесты с mock и интеграционные тесты с реальными объектами