Python: 我该如何模拟一个被多次调用的异步方法?

5

我有一个在Python(3.6)中测试异步代码的方法:

@asyncio.coroutine
def coroutine_creater(value):
    return value

我这样使用它:
async def test_test():
    my_mock = Mock(return_value=coroutine_creater(5))

    # I call with "await"
    first_call = await my_mock()
    second_call = await my_mock()

    assert first_call == 5, 'first call failed'
    assert second_call == 5, 'second call failed'  # this call fails

这样我就可以为异步调用创建模拟。但是我发现,如果我两次调用异步方法,它就不起作用了。在我的代码中,first_call 的值如预期的那样等于5,但是second_call的值为None。这是怎么回事?我该如何测试调用Mock异步方法多次的代码?


看起来我可以使用这个 https://dev59.com/8FwY5IYBdhLWcg3wkIYi#46326234 - user2023861
1个回答

2
你需要为 Mock 设置 `side_effect` 参数。

side_effect: 每当 Mock 被调用时调用的函数。请参见 side_effect 属性。有助于引发异常或动态更改返回值。该函数使用与 mock 相同的参数进行调用,除非它返回 DEFAULT,否则此函数的返回值将用作返回值。

下面是使用 pytest-asynciopytest 模块的示例:

code_53856568.py:

import asyncio


@asyncio.coroutine
def coroutine_creater(value):
    return value

test_code_53856568.py:

from unittest.mock import Mock
from code_53856568 import coroutine_creater
import pytest


@pytest.mark.asyncio
async def test_test():
    def coroutine_creater_side_effect():
        return coroutine_creater(5)

    my_mock = Mock(side_effect=coroutine_creater_side_effect)

    first_call = await my_mock()
    second_call = await my_mock()

    assert first_call == 5, 'first call failed'
    assert second_call == 5, 'second call failed'

单元测试结果与覆盖率报告:
(venv) ☁  python-codelab [master] ⚡  coverage run -m pytest /Users/ldu020/workspace/github.com/mrdulin/python-codelab/src/stackoverflow/53856568/test_code_53856568.py && coverage report -m --include="src/*"
===================================================================================================================== test session starts =====================================================================================================================
platform darwin -- Python 3.7.5, pytest-5.3.1, py-1.8.0, pluggy-0.13.1
rootdir: /Users/ldu020/workspace/github.com/mrdulin/python-codelab
plugins: asyncio-0.10.0
collected 1 item                                                                                                                                                                                                                                              

src/stackoverflow/53856568/test_code_53856568.py .                                                                                                                                                                                                      [100%]

====================================================================================================================== 1 passed in 0.04s ======================================================================================================================
Name                                               Stmts   Miss  Cover   Missing
--------------------------------------------------------------------------------
src/stackoverflow/53856568/code_53856568.py            3      0   100%
src/stackoverflow/53856568/test_code_53856568.py      11      0   100%
--------------------------------------------------------------------------------
TOTAL

在我的问题评论中,我链接了这个解决方案 https://dev59.com/8FwY5IYBdhLWcg3wkIYi#46326234。我一直在使用它。 - user2023861
这对我在Python 3.7中有效。自从引入AsyncMock后,在3.8+中可能不需要,但由于我仍在使用3.7,所以这是必需的。 - Joao Coelho

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接