Я бы предложил вводить макеты, используя pytest
приборы вместо ручного копирования. Приборы с функциональной областью (по умолчанию) переоценивают для каждого теста. Пример: предположим, что у вас есть модуль
# mod.py
def spam():
return eggs()
def eggs():
return "eggs"
и тест
from unittest.mock import patch
from mod import spam
@patch("mod.eggs")
def test_bacon(mock1):
mock1.return_value = "bacon"
assert spam() == "bacon"
, и теперь вы хотите преобразовать его в тестирование на bacon
и bacon with eggs
. Удалите патч внутри прибора:
import pytest
from unittest.mock import patch
from mod import spam
@pytest.fixture
def eggs_mock():
with patch("mod.eggs") as mock1:
yield mock1
def test_bacon(eggs_mock):
eggs_mock.return_value = "bacon"
assert spam() == "bacon"
def test_bacon_with_eggs(eggs_mock):
eggs_mock.return_value = "bacon with eggs"
assert spam() == "bacon with eggs"
Теперь у вас есть два разных макета функции mod.eggs
, по одному уникальному макету в каждом тесте.
unittest
тесты в стиле
Этот подход также работает с unittest
тестовыми классами, хотя внедрение более многословно, поскольку unittest.TestCase
s не принимает аргументы в тестовых методах. Это тот же подход, который описан в моего ответа . В приведенном ниже примере я сохраняю возвращаемое значение устройства eggs_mock
в атрибуте экземпляра Tests
с помощью дополнительного устройства autouse :
from unittest import TestCase
from unittest.mock import patch
import pytest
from mod import spam
@pytest.fixture
def eggs_mock():
with patch("mod.eggs") as mock1:
yield mock1
class Tests(TestCase):
@pytest.fixture(autouse=True)
def inject_eggs_mock(self, eggs_mock):
self._eggs_mock = eggs_mock
def test_bacon(self):
self._eggs_mock.return_value = "bacon"
assert spam() == "bacon"
def test_bacon_with_eggs(self):
self._eggs_mock.return_value = "bacon with eggs"
assert spam() == "bacon with eggs"