使用 unittest.mock.patch 测试 aiohttp 客户端

Posted

技术标签:

【中文标题】使用 unittest.mock.patch 测试 aiohttp 客户端【英文标题】:Testing aiohttp client with unittest.mock.patch 【发布时间】:2017-09-27 14:30:59 【问题描述】:

我使用 aiohttp 编写了一个简单的 HTTP 客户端,我正在尝试通过修补 aiohttp.ClientSessionaiohttp.ClientResponse 来测试它。但是,似乎unittest.mock.patch 装饰器不尊重我的异步代码。猜测一下,我会说这是某种命名空间不匹配。

这是一个最小的例子:

from aiohttp import ClientSession

async def is_ok(url:str) -> bool:
    async with ClientSession() as session:
        async with session.request("GET", url) as response:
            return (response.status == 200)

我正在使用异步装饰器进行测试,如this answer 中所述。所以这是我尝试的测试:

import unittest
from unittest.mock import MagicMock, patch

from aiohttp import ClientResponse

from my.original.module import is_ok

class TestClient(unittest.TestCase):
    @async_test
    @patch("my.original.module.ClientSession", spec=True)
    async def test_client(self, mock_client):
        mock_response = MagicMock(spec=ClientResponse)
        mock_response.status = 200

        async def _mock_request(*args, **kwargs):
            return mock_response

        mock_client.request = mock_response

        status = await is_ok("foo")
        self.assertTrue(status)

我的is_ok 协程在用于__main__ 时运行良好,但是当我运行测试时,它给了我一个错误,表明session.request 函数没有被我的patch 模拟称呼。 (具体来说,它说“无法从 URL 'foo' 解析主机名”,如果它没有被模拟,它应该这样做。)

我无法逃避这种行为。我试过了:

模拟完成后导入is_ok。 将模拟分配给mock_clientmock_client.__aenter__,将mock_client.request设置为MagicMock(return_value=mock_response),或使用mock_client().request等的各种组合。 使用特定的 __aenter____aexit__ 方法编写模拟 ClientSession,并在 new 参数中使用它 patch

这些似乎都没有影响。如果我将断言放入is_ok 以测试ClientSessionMagicMock 的一个实例,那么这些断言在我运行测试时会失败(同样,当代码未修补时它们也会失败)。这引出了我的命名空间不匹配理论:也就是说,事件循环在 patch 所针对的不同命名空间中运行。

要么这样,要么我在做一些愚蠢的事情!

【问题讨论】:

【参考方案1】:

不鼓励嘲笑ClientSession

推荐的方法是创建假服务器并向其发送真实请求。

看看aiohttp example。

【讨论】:

这就像一个测试数据库的使用,而不是模拟所有的 SQL 执行。 是的,一个集成测试。可以理解且必要,但如果您只想测试控制流,则可以说是矫枉过正。 不过你可以看看github.com/pnuckowski/aioresponses。 完美 :) 谢谢 我认为这不是问题的答案

以上是关于使用 unittest.mock.patch 测试 aiohttp 客户端的主要内容,如果未能解决你的问题,请参考以下文章

测试使用

第一篇 用于测试使用

如何在 testRigor 的一个测试中使用测试套件之前和测试套件之后?

Linux在测试中的主要使用场景都有哪些?

使用[测试类]而不是[编码UI测试]时将测试用例与测试方法相关联

3 测试使用和LogCat日志