不知道更多细节,我建议分开
my_patcher
几个小装置:
@pytest.fixture
def mocked_GET_pos(monkeypatch):
monkeypatch.setattr(ExternalLib, 'GET', lambda: True)
@pytest.fixture
def mocked_GET_neg(monkeypatch):
monkeypatch.setattr(ExternalLib, 'GET', lambda: False)
@pytest.fixture
def mocked_GET_raises(monkeypatch):
def raise_():
raise Exception()
monkeypatch.setattr(ExternalLib, 'GET', raise_)
现在使用
pytest.mark.usefixtures
要在测试中自动应用夹具:
@pytest.mark.usefixtures('mocked_GET_pos')
def test_GET_pos():
assert ExternalLib.GET()
@pytest.mark.usefixtures('mocked_GET_neg')
def test_GET_neg():
assert not ExternalLib.GET()
@pytest.mark.usefixtures('mocked_GET_raises')
def test_GET_raises():
with pytest.raises(Exception):
ExternalLib.GET()
但是,根据实际情况,还有改进的空间。例如,当测试逻辑相同且唯一不同的是某些测试先决条件(例如
GET
在您的情况下),测试或设备参数化通常可以节省大量的代码复制。假设您有一个调用
得到
内部:
# my_lib.py
def inform():
try:
result = ExternalLib.GET()
except Exception:
return 'error'
if result:
return 'success'
else:
return 'failure'
你想测试它是否返回一个有效的结果,不管是什么
得到
行为:
# test_my_lib.py
def test_inform():
assert inform() in ['success', 'failure', 'error']
使用上述方法,您需要复制
test_inform
三次,复印件之间唯一的区别是使用了不同的夹具。这可以通过编写一个可接受多个补丁的参数化夹具来避免。
得到
:
@pytest.fixture(params=[lambda: True,
lambda: False,
raise_],
ids=['pos', 'neg', 'exception'])
def mocked_GET(request):
monkeypatch.setattr(ExternalLib, 'GET', request.param)
现在申请时
mocked_GET
到
测试通知
:
@pytest.mark.usefixtures('mocked_GET')
def test_inform():
assert inform() in ['success', 'failure', 'error']
一个测试中有三个测试:
测试通知
将运行三次,每次模拟传递到
嘲弄
参数。
test_inform[pos]
test_inform[neg]
test_inform[exception]
测试也可以参数化(通过
pytest.mark.parametrize
)正确应用时,参数化技术节省了大量样板代码。