Python 使用 pytest 模拟修补另一个函数中的协程函数?

Oks*_*ana 5 python pytest python-asyncio

我在 module_name/app.py 中有两个函数

async def f1(arg):
    # do something
    return arg + '1'


async def f2(arg):
    result = await f1(arg)
    return result
Run Code Online (Sandbox Code Playgroud)

我尝试使用 pytest 和 asynctest 测试 f2 和模拟 f1。
只有我这样做才有效

def sf_f1(arg):
    return 'some value'

@pytest.mark.asyncio
async def test_f2():
    with asynctest.mock.patch('module_name.app.f1', side_effect=sf_f1):
        assert 'some value' == await f2('test')
Run Code Online (Sandbox Code Playgroud)

考试通过了

但是,我想做这样的事情

import module_name

@pytest.fixture()
def mock_f1():
    return asynctest.CoroutineMock(module_name.app.f1, side_effect=sf_f1)


@pytest.mark.asyncio
async def test_f2_2(mock_f1):
    assert 'some value' == await f2('test')
Run Code Online (Sandbox Code Playgroud)

我明白了

   assert 'some value' == await f2('test')
   AssertionError: assert 'some value' == 'test1'
     - some value
     + test1
Run Code Online (Sandbox Code Playgroud)

为什么第二种方法不起作用?

Mar*_*oft 4

在第二个示例中,在mock_f1固定装置中创建一个CoroutineMock对象并返回它。但你不会覆盖module_name.app.f1function: Mock-like 对象不会自动修补任何内容。

这是对您的示例的说明性补充:

@pytest.mark.asyncio
async def test_f2_2(mock_f1):
    print('fixture value:', mock_f1)
    print('actual module_name.app.f1 function:', module_name.app.f1)
    assert 'some value' == await f2('test')
Run Code Online (Sandbox Code Playgroud)

这会打印出像这样的东西

fixture value: <CoroutineMock spec='function' id='139756096130688'>
actual module_name.app.f1 function: <function f1 at 0x7f1b7e1139d8>
Run Code Online (Sandbox Code Playgroud)

当您调用 时f2,它使用f1模块中的函数,该函数未被覆盖。

所以这对你来说是这样的:

@pytest.fixture
def mock_f1(monkeypatch):
    fake_f1 = asynctest.CoroutineMock(module_name.app.f1, side_effect=sf_f1)
    monkeypatch.setattr(module_name.app, 'f1', fake_f1)
    return fake_f1
Run Code Online (Sandbox Code Playgroud)

您可能知道,monkeypatch将确保仅在夹具处于活动状态时应用更改。