Мок-объекты - это объекты, имитирующие поведение реальных зависимостей в ваших тестах. Они позволяют изолировать тестируемый код от внешних факторов (баз данных, API и т.д.), делая тесты быстрее, детерминированными и более контролируемыми.
Применение в тестах:
Пример (Python `unittest.mock`):
from unittest.mock import Mock
def my_function(dependency):
return dependency.do_something(123)
mock_dependency = Mock()
mock_dependency.do_something.return_value = 'mocked_result'
result = my_function(mock_dependency)
assert result == 'mocked_result'
mock_dependency.do_something.assert_called_once_with(123)
Мок-объекты (mock objects) - это объекты, имитирующие поведение реальных зависимостей (например, других классов, модулей, внешних сервисов, баз данных) в ваших тестах. Они позволяют изолировать тестируемый код от этих зависимостей, чтобы можно было сосредоточиться на проверке его логики, не беспокоясь о внешних факторах.
Зачем использовать мок-объекты?
Как использовать мок-объекты в тестах Python?
В Python для создания и использования мок-объектов обычно используют библиотеку unittest.mock (доступна в стандартной библиотеке Python 3.3+). До Python 3.3 часто использовали стороннюю библиотеку mock (теперь unittest.mock).
Основные понятия unittest.mock:
Mock: Наиболее универсальный класс для создания мок-объектов. Позволяет имитировать любые атрибуты и методы.MagicMock: Подкласс Mock, который предоставляет "магические методы" (например, __str__, __len__) с дефолтной реализацией, что упрощает мокирование объектов с такими методами.patch: Декоратор или контекстный менеджер, который позволяет заменить объект (класс, функция, атрибут) в модуле на мок во время теста. Очень удобен для временной замены зависимостей.Пример:
Предположим, у нас есть функция, которая взаимодействует с внешним API:
import requests
def get_data_from_api(url):
try:
response = requests.get(url)
response.raise_for_status() # Raise HTTPError for bad responses (4xx or 5xx)
data = response.json()
return data
except requests.exceptions.RequestException as e:
print(f"Error fetching data: {e}")
return None
Чтобы протестировать эту функцию без реального вызова API, мы можем использовать мок:
import unittest
from unittest.mock import patch, MagicMock
import your_module # Замените на имя вашего модуля, содержащего get_data_from_api
class TestGetDataFromApi(unittest.TestCase):
@patch('your_module.requests.get')
def test_get_data_from_api_success(self, mock_get):
# Настраиваем поведение мока
mock_response = MagicMock()
mock_response.json.return_value = {'key': 'value'}
mock_response.raise_for_status.return_value = None # To simulate successful response
mock_get.return_value = mock_response
# Вызываем тестируемую функцию
result = your_module.get_data_from_api('https://example.com/api')
# Проверяем, что функция вернула ожидаемый результат
self.assertEqual(result, {'key': 'value'})
# Проверяем, что mock_get был вызван с правильным аргументом
mock_get.assert_called_once_with('https://example.com/api')
@patch('your_module.requests.get')
def test_get_data_from_api_failure(self, mock_get):
# Настраиваем поведение мока для случая ошибки
mock_get.side_effect = requests.exceptions.RequestException("Simulated error")
# Вызываем тестируемую функцию
result = your_module.get_data_from_api('https://example.com/api')
# Проверяем, что функция вернула None в случае ошибки
self.assertIsNone(result)
if __name__ == '__main__':
unittest.main()
В этом примере:
@patch('your_module.requests.get') заменяет функцию requests.get на мок-объект во время теста.mock_get:
test_get_data_from_api_success мы возвращаем мок-объект mock_response, который имитирует успешный ответ API (с json методом, возвращающим словарь). Мы также настраиваем raise_for_status чтобы избежать исключений.test_get_data_from_api_failure мы задаем side_effect для mock_get, чтобы имитировать возникновение исключения requests.exceptions.RequestException.get_data_from_api.None (в случае ошибки).mock_get.assert_called_once_with('https://example.com/api') проверяет, что мок-объект mock_get был вызван ровно один раз с ожидаемым аргументом.Другие возможности unittest.mock:
side_effect: Позволяет задать функцию или исключение, которое будет возвращаться при вызове мок-объекта. Это полезно для имитации различных сценариев, включая ошибки.return_value: Задает значение, которое будет возвращаться при вызове мок-объекта.assert_called(), assert_called_once(), assert_called_with(), assert_called_once_with(): Методы для проверки того, был ли вызван мок-объект, сколько раз он был вызван и с какими аргументами.call, call_args_list: Позволяют анализировать вызовы мок-объекта.Использование мок-объектов - важная часть юнит-тестирования, позволяющая создавать более надежные, быстрые и воспроизводимые тесты.