考虑我的模块"mymodule.py"
# contents of "mymodule.py"
def func1(x):
return x * 2
我想模仿这个函数并改变它的返回。根据文档,我可以这样做:
# contents of "test_mymodule.py"
import mymodule
import pytest
@pytest.fixture
def mock_func1():
def mock_ret(*args, **kwargs):
return 2
def test_func1_a(monkeypatch, mock_func1):
monkeypatch.setattr(mymodule, "func1", mock_func1)
assert mymodule.func1(1) == 2
def test_func1_b(monkeypatch, mock_func1):
monkeypatch.setattr(mymodule, "func1", mock_func1)
assert mymodule.func1(1) != 37
但是,我不想为每个测试修补模块。对于整个测试模块monkeypatch.setattr
的范围,test_mymodule.py
一次的正确方法是什么?
我期待这样的事情
# contents of "test_mymodule.py"
import mymodule
import pytest
@pytest.fixture
def mock_func1():
def mock_ret(*args, **kwargs):
return 2
monkeypatch.setattr(mymodule, "func1", mock_func1)
def test_func1_a():
assert mymodule.func1(1) == 2
def test_func1_b():
assert mymodule.func1(1) != 37
但是这让我
NameError: name 'monkeypatch' is not defined
答案 0 :(得分:1)
直接从pytest被盗:
import mymodule
import pytest
def wildpatch(target, name, value=None, raising=True):
import inspect
if value is None:
if not isinstance(target, _basestring):
raise TypeError("use setattr(target, name, value) or "
"setattr(target, value) with target being a dotted "
"import string")
value = name
name, target = derive_importpath(target, raising)
oldval = getattr(target, name, None)
if raising and oldval is None:
raise AttributeError("%r has no attribute %r" % (target, name))
# avoid class descriptors like staticmethod/classmethod
if inspect.isclass(target):
oldval = target.__dict__.get(name, None)
setattr(target, name, value)
##@pytest.fixture
##def mock_func1():
## def mock_ret(*args, **kwargs):
## print("monkeypatched func1")
## return 2
def mock_func1(*args, **kwargs):
print("monkeypatched func1")
return 2
wildpatch(mymodule, "func1", mock_func1)
def test_func1_a():
print("Running test_func1_a")
assert mymodule.func1(1) == 2
def test_func1_b():
assert mymodule.func1(1) != 37
运行python -m pytest -s test.py
收益
=============================== test session starts ================
platform linux -- Python 3.4.3, pytest-3.1.2, py-1.4.34, pluggy-0.4.0
rootdir: /tmp/ab, inifile:
collected 2 items
test.py Running test_func1_a
monkeypatched func1
.monkeypatched func1
.
=========================== 2 passed in 0.01 seconds ===============================
我猜你想要的只是将func1重定向到你自己的函数。
答案 1 :(得分:1)
只是碰到了这个答案,因为我正在尝试做类似的事情。您可以使用这样的装饰器对测试进行预处理。可以在mock_func_1_in_test
装饰器下面添加其他pytest装饰器。
# contents of "test_mymodule.py"
import mymodule
import pytest
@pytest.fixture
def mock_func1():
def mock_ret(*args, **kwargs):
return 2
return mock_ret
def mock_func_1_in_test(func):
def inner(monkeypatch, mock_func1, *args, **kwargs):
monkeypatch.setattr(mymodule, "func1", mock_func1)
return func(*args, **kwargs)
return inner
@mock_func_1_in_test
def test_func1_a():
assert mymodule.func1(1) == 2
@mock_func_1_in_test
def test_func1_b():
assert mymodule.func1(1) != 37
这可以按您期望的那样工作:
$ pytest
================================== test session starts ===================================
platform darwin -- Python 3.6.6, pytest-3.6.0, py-1.6.0, pluggy-0.6.0
rootdir: /Users/delgadom/git/messin/pytest_test, inifile:
plugins: cov-2.5.1
collected 2 items
test_mymodule.py .. [100%]
================================ 2 passed in 0.03 seconds ================================