pytest 中的全局夹具

问题描述 投票:0回答:1

问题

我想用尽可能少的样板来模拟我的一个功能。

项目设置

在我的(简化的)项目中,我有以下文件/函数:

  • utils.py
    ,带有函数
    get_id(param1, param2)
    (这就是我想嘲笑的)
  • work.py
    具有功能
    do_work()
    导入和使用
    utils.get_id
  • tests/test_work.py
    进行以下测试:
from work import do_work

def test_work():
  # somehow have get_id patched
  ...
  do_work()
    ...

解决方案

简单,样板太多

get_id
模块修补
work
非常容易。请注意,无论最终解决方案是什么,参数都很重要,因此
return_value
不起作用。

from work import do_work
import mock

def mock_id(param1, param2): return f"{param1} {param2}"

def test_work():
  with mock.path("work.get_id", side_effect=mock_id):
    ...
    do_work()
    ...

# A variation is:

@patch("work.get_id", side_effect=mock_id)
def test_another_work(mock_id):
  ...

确实有效,但有很多样板:

  • 需要在每个测试文件中定义或导入
    mock_id()
  • 需要完整的
    patch
    行,并且可能需要测试函数的无用参数
  • 被测试的模块是打过补丁的,所以每个测试文件都会不同,因为很多模块都使用了
    get_id()

conftest.py
和全局夹具

我可以添加一个

conftest.py
文件,一劳永逸地定义 pytest 夹具

@pytest.fixture()
def _get_id():
    def mock_get_id(param1, param2):
        return f"{param1} {param2}"
    with mock.patch("utils.get_id", side_effect=mock_get_id):
        yield

我想我可以这样写我的测试:

@pytest.mark.usefixtures("_get_id")
def test_work():
  ...

我明确地不希望它与

autouse=True
一起使用,而这一条
@pytest.mark.usefixtures("_get_id")
行在我看来像是样板文件和明确性之间的良好平衡。

替代装置

环顾四周,这看起来也可以起作用:

@pytest.fixture()
def _get_id(monkeypatch):
    def mock_get_id(param1, param2):
        return f"{param1} {param2}"
    monkeypath("utils.get_id", mockget_id):

问题

固定装置被调用、使用,但始终使用原始 get_id,而不是模拟版本。如何确保

get_id
已全局修补?

python python-3.x unit-testing pytest monkeypatching
1个回答
0
投票

在 Python 中,当使用

from foo import get_id
将函数导入到多个位置时,通常不可能将其替换为另一个函数。 (请参阅
unittest.mock
的文档中的“修补位置”。
)(从技术上讲,您可以非常棘手地用另一个对象替换函数的内部代码对象,但这会危险地进入黑魔法领域。)

如果这是关于单个

get_id
,我建议将其做成蹦床:

_test_get_id = None
def get_id(x):
    if _test_get_id:  # For ease of testing
        return _test_get_id(x)
    ...  # usual implementation

现在,您可以使用任何您想要设置

_test_get_id
的方法(例如,仅
monkeypatch.setattr
),所有对
get_id
的调用,无论它们可能已被导入,最终都将使用
_test_get_id

© www.soinside.com 2019 - 2024. All rights reserved.