mock.patch()
:
'module.object_to_replace'
).mock.patch()
как декоратор, контекстный менеджер или вызовите его непосредственно, передав путь к объекту.
from unittest.mock import patch
@patch('module.object_to_replace')
def test_function(mock_object):
# mock_object - это мок, заменяющий module.object_to_replace
mock_object.return_value = 'mocked_value'
result = my_function_using_object()
assert result == 'mocked_value'
mock.patch()
- это мощный инструмент из библиотеки unittest.mock
, который позволяет временно заменять объекты (классы, функции, атрибуты) в тестах, чтобы контролировать их поведение и изолировать тестируемый код от внешних зависимостей. Это особенно полезно, когда нужно имитировать взаимодействие с внешними API, базами данных, или другими частями системы, которые сложно или нежелательно подключать к тестам.
Как работает mock.patch()
:
mock.patch()
- это строка, представляющая путь к объекту, который нужно заменить. Путь указывается в формате 'module.object'
. module
- это имя модуля, а object
- имя объекта внутри этого модуля.mock.patch()
заменяет оригинальный объект фиктивным объектом (Mock
или другим указанным вами). Этот фиктивный объект можно настроить для возвращения определенных значений, вызывать определенные исключения или выполнять любые другие действия.mock.patch()
можно использовать как контекстный менеджер (с with
) или как декоратор для тестовой функции или класса. Использование контекстного менеджера гарантирует, что патч автоматически отменяется после завершения блока with
. Декоратор патчит объект на время выполнения тестовой функции.mock.patch()
используется как контекстный менеджер или декоратор, он автоматически передает Mock-объект как аргумент в блок with
или в тестовую функцию. Этот Mock-объект можно использовать для проверки, как был вызван замененный объект (mock.call
, mock.called
, mock.assert_called_with()
и т.д.).mock.patch()
гарантирует, что оригинальный объект будет восстановлен после завершения теста или блока with
. Это важно, чтобы не повлиять на другие тесты или код.Примеры:
Пример 1: Использование как контекстного менеджера
import unittest
from unittest.mock import patch
# Представим, что модуль external_api содержит функцию get_data()
# которую мы хотим заменить в тесте.
import external_api
class MyTest(unittest.TestCase):
def test_my_function(self):
with patch('external_api.get_data') as mock_get_data:
# Настраиваем Mock-объект (mock_get_data)
mock_get_data.return_value = "Mocked data"
# Вызываем тестируемый код, который использует external_api.get_data()
result = my_function_that_uses_external_api()
# Проверяем, что external_api.get_data() был вызван (и, возможно, с какими-то аргументами)
mock_get_data.assert_called_once()
# Проверяем результат тестируемого кода
self.assertEqual(result, "Expected result based on mocked data")
Пример 2: Использование как декоратора
import unittest
from unittest.mock import patch
import external_api
class MyTest(unittest.TestCase):
@patch('external_api.get_data')
def test_my_function(self, mock_get_data):
# mock_get_data - это Mock-объект, переданный декоратором
mock_get_data.return_value = "Mocked data"
result = my_function_that_uses_external_api()
mock_get_data.assert_called_once()
self.assertEqual(result, "Expected result based on mocked data")
Пример 3: Замена атрибута класса:
import unittest
from unittest.mock import patch
class MyClass:
CONSTANT = "Original Value"
def do_something(self):
return self.CONSTANT
class TestMyClass(unittest.TestCase):
@patch('__main__.MyClass.CONSTANT', "Mocked Value") # __main__ - имя текущего модуля
def test_do_something(self):
instance = MyClass()
self.assertEqual(instance.do_something(), "Mocked Value")
Важные моменты:
mock.patch()
. Проблемы с видимостью часто возникают при использовании относительных импортов.return_value
, side_effect
(для вызова функции или выброса исключения), mock_add_spec
(для имитации интерфейса другого объекта) и т.д.assert_called_once()
, assert_called_with()
, call_args
и другие методы Mock-объекта, чтобы убедиться, что замененный объект был вызван так, как ожидалось, и с правильными аргументами. Это гарантирует, что тестируемый код правильно использует замененную зависимость.side_effect
для Mock-объекта, важно тщательно управлять побочными эффектами, чтобы тесты оставались предсказуемыми и изолированными.autospec
: Параметр autospec=True
для mock.patch
позволяет автоматически создавать Mock-объект, который имеет ту же сигнатуру и атрибуты, что и оригинал. Это помогает избежать ошибок, связанных с неправильной конфигурацией Mock-объекта, и делает тесты более надежными. Например: @patch('module.function', autospec=True)
.В заключение, mock.patch()
- это незаменимый инструмент для написания модульных тестов на Python. Правильное использование mock.patch()
позволяет изолировать тестируемый код от внешних зависимостей, контролировать его поведение и писать надежные и воспроизводимые тесты.