Мок-объекты - это объекты, имитирующие поведение реальных зависимостей в ваших тестах. Они позволяют изолировать тестируемый код от внешних факторов (баз данных, 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
: Позволяют анализировать вызовы мок-объекта.Использование мок-объектов - важная часть юнит-тестирования, позволяющая создавать более надежные, быстрые и воспроизводимые тесты.