适用于协程的Python 3.8模拟

时间:2019-11-10 19:30:35

标签: python-3.x python-asyncio python-unittest

我尝试编写unittest来检查是否确定了类方法。

class Application:
    async def func1(self):
        await self.func2(self.func3())

    async def func2(self, val):
        pass

    async def func3(self):
        pass

并对其进行单元测试:

@pytest.mark.asyncio
async def test_method():
    app = Application()

    with patch.object(Application, 'func2') as mock:
        await app.func1()
        mock.assert_awaited_with(app.func3())

但是我得到了错误:

AssertionError: expected await not found.
Expected: func2(<coroutine object Application.func3 at 0x7f1ecf8557c0>)
Actual: func2(<coroutine object Application.func3 at 0x7f1ecf855540>)

为什么?我调用了相同的方法。我该怎么办?

1 个答案:

答案 0 :(得分:0)

有一个asynctest,可以更轻松地模拟(修补)异步函数。

  

修补

     

修补是一种允许临时替换符号的机制   (类,对象,函数,属性等)通过模拟就地进行。它是   当需要模拟但无法通过模拟时特别有用   要测试的功能的参数。

     

例如,如果cache_users()不接受客户端参数,但   而是创建了一个新客户端,将无法替换它   像之前所有示例中的模拟一样。

     

当难以模拟对象时,有时会在   设计:太紧的联轴器,使用全局变量(或   单例)等。但是,并非总是可能或不希望   更改代码以适应测试。常见的情况是   执行记录或   监控。在这种情况下,打补丁会有所帮助。

     

patch()可用作上下文管理器。它将取代目标   (logging.debug())在with块的生存期内进行了模拟。

async def test_with_context_manager(self):
    client = asynctest.Mock(AsyncClient())
    cache = {}

    with asynctest.patch("logging.debug") as debug_mock:
        await cache_users_async(client, cache)

    debug_mock.assert_called()

请注意,函数的路径是作为asynctest.patch的字符串而不是作为对象给出的。

此外,在func1 func2中将func3用作协程,并且不等待它运行(不等待)。

您可以尝试这样的事情:

import asynctest
@pytest.mark.asyncio
async def test_method():
    app = Application()

    with asynctest.patch('Application.func2') as mock:
        await app.func1()
    mock.assert_awaited_with(app.func3())