Python Pytest:使用无副作用的函数设置模拟
关于这个问题的答案,我有一个问题: 我喜欢使用通过参数接收模拟对象的函数。这样,可以重用模拟的设置。我从答案中得出结论,在Python中模拟对象是可变的,在函数内部更改它们将产生副作用,即它们在外部更改。但是,我认为副作用是危险的。因此,我建议如下:Python Pytest:使用无副作用的函数设置模拟,python,mocking,pytest,Python,Mocking,Pytest,关于这个问题的答案,我有一个问题: 我喜欢使用通过参数接收模拟对象的函数。这样,可以重用模拟的设置。我从答案中得出结论,在Python中模拟对象是可变的,在函数内部更改它们将产生副作用,即它们在外部更改。但是,我认为副作用是危险的。因此,我建议如下: def test(self, mock1): mock1 = setup_mock1_to_always_xxx(mock1) ... 与 这可能吗?我建议使用注入模拟,而不是手动模拟复制。功能范围内的装置(默认装置)将为每个测
def test(self, mock1):
mock1 = setup_mock1_to_always_xxx(mock1)
...
与
这可能吗?我建议使用注入模拟,而不是手动模拟复制。功能范围内的装置(默认装置)将为每个测试重新评估。示例:假设您有一个模块
# 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"
现在,您需要将其重构为针对培根
和培根鸡蛋
进行测试。移出夹具内的修补:
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\u mock
fixture返回值存储在Tests
实例属性中:
只是设置另一个模拟而不是复制不是更容易吗<在您的示例中,code>mock1可以是一个fixture,它的函数作用域将在执行每个测试之前被调用,因此每个测试都会得到一个新的mock。@hoefling,我认为这是最优雅的答案。你想从你的评论中做出一个回答吗,也许可以举个例子?我不想拿你的学分,否则我会做的。
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"
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"