【问题标题】:Python 3.8 mock for coroutines用于协程的 Python 3.8 模拟
【发布时间】:2019-11-10 19:30:35
【问题描述】:

我尝试编写 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>)

为什么?我调用了同样的方法。我能用它做什么?

【问题讨论】:

  • 它期待相同的身份,而不是平等。再次调用该方法会给你一个不同的对象。
  • 我应该将协程传递给方法,我怎样才能给不同的对象?

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


【解决方案1】:

有一个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())

【讨论】:

    猜你喜欢
    • 2017-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-26
    • 2015-07-05
    • 1970-01-01
    • 2019-04-12
    • 2020-11-09
    相关资源
    最近更新 更多