Ответ
Мокирование (подмена) запросов — это ключевая техника для создания изолированных, быстрых и стабильных тестов. Основные причины её использования:
- Изоляция тестируемого модуля: Позволяет тестировать логику клиентского кода или сервиса, не завися от работы реального внешнего API, базы данных или другого микросервиса. Если тот «упал» или изменился, мои тесты всё равно будут проходить.
- Тестирование сложных и редких сценариев: Я могу легко смоделировать ответы, которые сложно или невозможно получить от реального сервиса в тестовом окружении.
- Ошибки сервера: 500 Internal Server Error, 503 Service Unavailable.
- Нестандартные ответы: Очень большие данные, специфичные форматы, медленные ответы (таймауты).
- Edge-кейсы: Ответ с пустым телом, невалидный JSON.
- Ускорение выполнения тестов: Моки работают в памяти, что в сотни раз быстрее, чем реальные сетевые вызовы.
- Предотвращение side-эффектов: Тест не создаст запись в реальной продакшн-БД или не отправит настоящее SMS-сообщение.
Практический пример (Python, pytest с pytest-mock):
Допустим, у меня есть функция get_user_data(user_id), которая внутри делает HTTP-запрос. Я хочу протестировать её логику обработки ответа.
import pytest
import requests
# Функция, которую тестируем
def get_user_data(user_id):
response = requests.get(f"https://api.example.com/users/{user_id}")
if response.status_code == 200:
return response.json()["data"]
elif response.status_code == 404:
return None
else:
raise Exception("API Error")
# Сам тест с моком
def test_get_user_data_success(mocker): # 'mocker' — фикстура из pytest-mock
# 1. Создаём мок-ответ, который имитирует успешный API-ответ
mock_response = mocker.Mock()
mock_response.status_code = 200
mock_response.json.return_value = {"data": {"id": 123, "name": "Alice"}}
# 2. Подменяем реальный `requests.get` на наш мок
# Теперь при вызове requests.get() в функции вернётся mock_response
mocker.patch("requests.get", return_value=mock_response)
# 3. Вызываем тестируемую функцию
result = get_user_data(123)
# 4. Проверяем, что функция корректно обработала мок-ответ
assert result == {"id": 123, "name": "Alice"}
# Дополнительно можно проверить, что запрос был вызван с правильным URL
# requests.get.assert_called_once_with("https://api.example.com/users/123")
def test_get_user_data_not_found(mocker):
mock_response = mocker.Mock()
mock_response.status_code = 404
mocker.patch("requests.get", return_value=mock_response)
result = get_user_data(999)
assert result is None # Проверяем обработку 404 ошибки
Важно помнить, что моки должны максимально точно имитировать поведение реального сервиса, и их стоит использовать для unit- и component-тестов. Для интеграционного и end-to-end тестирования предпочтительнее использовать реальные сервисы или их точные стабы (stubs).