Ответ
Мокирование (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") Ответ 18+ 🔞
А, вот эта тема про мокирование! Ну, это когда ты, блядь, в тестах не хочешь, чтобы всякая хуйня мешала — типа базы данных, которая может лежать, или апишки, которая тебе в ответ плюнет. Вместо них подсовываешь подставных уродов, которые делают только то, что ты им скажешь. Красота, ёпта!
Зачем это, спрашивается, надо, блядь?
- Чтобы не охуеть от неожиданностей. Мок — он как дрессированная мартышка: скажешь «принеси банан» — принесёт банан, а не нассет тебе в тапок, как это делает реальная система в пятницу вечером.
- Чтобы не ждать, как дурак. Запрос к настоящему 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"
И вот ты такой: «Хочу её потестить, но на реальный запрос идти — терпения ноль ебать, да и интернета может не быть». Берёшь и подменяешь requests.get своей куклой!
from unittest import TestCase
from unittest.mock import patch
# Тест
class WeatherTest(TestCase):
@patch('__main__.requests.get') # Вот тут мы и говорим: "Слушай, Python, вместо настоящего 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")
Видишь, какая магия? Функция думает, что сходит в интернет, а на самом деле пообщалась с нашим подставным актёром. И мы точно знаем, что она его вызвала с правильным URL и правильно разобрала его фейковый ответ. Всё чисто, изолированно и быстро, как удар током.