我在src/utils/helper.py
有一些utils函数
想象一下,在utils / helper.py中有一个名为func_a
的函数,并且该函数在我项目的多个位置使用。
每次使用时,我都会这样导入
from src.utils.helper import func_a
现在我想在测试中模拟这个func_a
。
我想在conftest.py中创建一个固定装置,这样我就不需要为每个测试文件一次又一次地编写模拟函数。
问题是,在我的模拟函数中,我不能这样写。
https://pypi.org/project/pytest-mock/
mocker.patch('src.utils.helper.func_a', return_value="some_value", autospec=True)
对于每个测试文件,我都必须这样写
mocker.patch('src.pipeline.node_1.func_a', return_value="some_value", autospec=True)
根据文档https://docs.python.org/3/library/unittest.mock.html#where-to-patch
由于我像func_a
一样导入from src.utils.helper import func_a
,因此我不得不模拟使用它的地方,而不是定义它的地方。
但是这种方法的问题是我无法在conftest.py的夹具中定义它。
目录结构
├── src
│ ├── pipeline
│ │ ├── __init__.py
│ │ ├── node_1.py
│ │ ├── node_2.py
│ │ └── node_3.py
│ └── utils
│ ├── __init__.py
│ └── helper.py
└── tests
├── __init__.py
├── conftest.py
└── pipeline
├── __init__.py
├── test_node_1.py
├── test_node_2.py
└── test_node_3.py
答案 0 :(得分:2)
好吧,正如您所写,如果您使用g(x).is_constant() == None
,则必须使用修补程序 。您的第一个选择当然是在生产代码中使用完整的模块导入:
node_1.py
g(C,x).is_constant() == None
我确定您已经意识到这一点,但是无论如何我想提一下。
如果您不想更改生产代码,则必须按照所编写的修补模块进行修补。这基本上意味着您必须动态构建补丁程序位置。假设您对测试功能和测试功能具有对称的命名,则可以执行以下操作:
conftest.py
from xxx import
如果无法从测试本身获得补丁路径,则必须向测试功能添加更多信息。
如果您想做的不仅仅是固定装置中的补丁,那可能只有道理-否则您也可以直接添加import src.utils.helper
def node_1():
src.utils.helper.func_a()
装饰器。
您可以添加具有模块路径或部分模块路径作为参数的自定义标记:
test_node_1.py
@pytest.fixture
def mock_func_a(mocker, request):
node_name = request.node.name[5:] # we assume that the test function name is "test_node_1" for testing "node_1"
module_path = f'src.pipeline.{node_name}.func_a'
mocked = mocker.patch(module_path,
return_value="some_value",
autospec=True)
yield mocked
conftest.py
patch
或者,如果您需要提供完整路径:
test_node_1.py
@pytest.mark.node("node_1")
def test_node(mock_func_a):
node_1()
mock_func_a.assert_called_once()
conftest.py
@pytest.fixture
def mock_func_a(mocker, request):
mark = next((m for m in request.node.iter_markers()
if m.name == 'node'), None) # find your custom mark
if mark is not None:
node_name = mark.args[0]
module_path = f'src.pipeline.{node_name}.func_a'
mocked = mocker.patch(module_path,
return_value="some_value",
autospec=True)
yield mocked