Ответ
Мокирование (mocking) — это техника в юнит-тестировании, при которой реальные зависимости объекта (например, модули для работы с базой данных, внешние API, файловая система) заменяются на управляемые объекты-заглушки (моки).
Основная цель — изолировать тестируемый код (SUT - System Under Test), чтобы проверить его логику в отрыве от внешних систем.
Зачем это нужно:
- Предсказуемость: Мок всегда возвращает заранее определенные данные, что делает тест стабильным.
- Скорость: Тесты выполняются быстрее, так как нет реальных сетевых запросов или обращений к диску.
- Изоляция: Ошибки в зависимостях не влияют на результаты теста, проверяется только логика самого юнита.
- Тестирование крайних случаев: Легко имитировать ошибки (например, недоступность сети или пустой ответ от БД) и проверить, как код их обрабатывает.
Пример с unittest.mock
в Python:
Допустим, у нас есть функция, которая получает данные о погоде с внешнего API.
import requests
def get_weather_description(city: str) -> str:
try:
response = requests.get(f"https://api.weather.com/{city}")
response.raise_for_status() # Вызовет исключение для плохих статусов
data = response.json()
return data['weather']['description']
except requests.RequestException:
return "Weather data unavailable"
Чтобы протестировать эту функцию без реального HTTP-запроса, мы «мокируем» requests.get
:
from unittest import TestCase
from unittest.mock import patch
# Тест
class WeatherTest(TestCase):
@patch('__main__.requests.get') # Указываем путь к объекту для мокирования
def test_get_weather_description_success(self, mock_get):
# 1. Настраиваем поведение мока
mock_response = mock_get.return_value
mock_response.json.return_value = {"weather": {"description": "Sunny"}}
mock_response.raise_for_status.return_value = None
# 2. Вызываем тестируемую функцию
description = get_weather_description("London")
# 3. Проверяем результат и вызовы
self.assertEqual(description, "Sunny")
mock_get.assert_called_once_with("https://api.weather.com/London")