Mock-объекты (или "моки") — это специальные объекты-заглушки, которые имитируют поведение реальных объектов в тестах. Они позволяют изолировать тестируемый код от внешних зависимостей.
Стандартный модуль unittest.mock
(входит в стандартную библиотеку Python):
from unittest.mock import Mock
# Создание mock-объекта
mock = Mock()
# Установка возвращаемого значения
mock.some_method.return_value = 42
# Вызов метода
result = mock.some_method()
assert result == 42
from unittest.mock import MagicMock
mock_dict = MagicMock()
mock_dict.__getitem__.return_value = "value"
assert mock_dict["key"] == "value"
mock = Mock()
mock.method(1, 2, 3, key="value")
# Проверка что метод был вызван
mock.method.assert_called()
# С конкретными аргументами
mock.method.assert_called_with(1, 2, 3, key="value")
# Сколько раз вызывался
assert mock.method.call_count == 1
Чаще всего используется через декоратор или контекстный менеджер:
from unittest.mock import patch
def external_api_call():
# Предположим, это обращение к внешнему API
return "real response"
@patch("__main__.external_api_call")
def test_mocked_api(mock_api):
mock_api.return_value = "mocked response"
result = external_api_call()
assert result == "mocked response"
Создает mock с теми же атрибутами, что и оригинальный объект:
from unittest.mock import create_autospec
def my_function(x, y):
return x + y
mock_func = create_autospec(my_function)
mock_func(1, 2) # Ок
mock_func(1) # Вызовет TypeError (не хватает аргументов)
Могут возвращать разные значения или вызывать исключения:
mock = Mock()
mock.side_effect = [1, 2, ValueError("Boom!")]
assert mock() == 1
assert mock() == 2
with pytest.raises(ValueError, match="Boom!"):
mock()
with patch("module.ClassName") as MockClass:
instance = MockClass.return_value
instance.method.return_value = "foo"
obj = module.ClassName()
assert obj.method() == "foo"
Тестирование сервиса, работающего с базой данных:
from unittest.mock import patch, MagicMock
import pytest
def get_user_from_db(user_id):
# Реальный вызов к базе данных
pass
@patch("module.get_user_from_db")
def test_user_service(mock_db):
# Настраиваем mock для разных сценариев
mock_db.return_value = {"id": 1, "name": "Test User"}
user = get_user_from_db(1)
assert user["name"] == "Test User"
# Проверяем что функция была вызвана с правильным аргументом
mock_db.assert_called_once_with(1)
Mock-объекты — мощный инструмент для unit-тестирования, позволяющий:
Главное правило: используйте моки разумно, не превращая тесты в проверку работы самих моков. Хороший тест проверяет логику кода, а не реализацию моков.