代码之家  ›  专栏  ›  技术社区  ›  vwos

使用aiohtp和asyncio时编写单元测试

  •  7
  • vwos  · 技术社区  · 6 年前

    我正在更新我的一个python包,因此它是异步的(使用 aiohttp 而不是 requests )我也在更新我的单元测试,以便它们与新的异步版本一起工作,但是我在这方面遇到了一些问题。

    以下是我的包中的一个片段:

    async def fetch(session, url):
        while True:
            try:
                async with session.get(url) as response:
                    assert response.status == 200
                    return await response.json()
            except Exception as error:
                pass
    
    
    class FPL():
        def __init__(self, session):
            self.session = session
    
        async def get_user(self, user_id, return_json=False):
            url = API_URLS["user"].format(user_id)
            user = await fetch(self.session, url)
    
            if return_json:
                return user
            return User(user, session=self.session)
    

    当使用时,它们似乎都起作用:

    async def main():
        async with aiohttp.ClientSession() as session:
             fpl = FPL(session)
             user = await fpl.get_user(3808385)
             print(user)
    
    loop = asynio.get_event_loop()
    loop.run_until_complete(main())
    
    >>> User 3808385
    

    不幸的是,我的单元测试有些问题。我想我可以做一些像

    def _run(coroutine):
        return asyncio.get_event_loop().run_until_complete(coroutine)
    
    
    class FPLTest(unittest.TestCase):
        def setUp(self):
            session = aiohttp.ClientSession()
            self.fpl = FPL(session)
    
        def test_user(self):
            user = _run(self.fpl.get_user("3523615"))
            self.assertIsInstance(user, User)
    
            user = _run(self.fpl.get_user("3523615", True))
            self.assertIsInstance(user, dict)
    
    if __name__ == '__main__':
        unittest.main()
    

    它会产生错误,例如

    DeprecationWarning: The object should be created from async function loop=loop)
    

    ResourceWarning: Unclosed client session <aiohttp.client.ClientSession object at 0x7fbe647fd208>
    

    我尝试添加 _close() 函数到 FPL 类关闭会话,然后从测试中调用它,但这也不起作用,仍然表示存在未关闭的客户端会话。

    有可能这样做吗?我只是做错了什么事,还是我最好用一下 asynctest pytest-aiohttp 相反?

    编辑:我也检查过 AIOHTTP 的文档并找到 example 演示如何使用标准库的UnitTest测试应用程序。不幸的是,我不能让它工作,因为 loop 提供在 AioHTTPTestCase 自3.5以来已弃用,并引发错误:

    class FPLTest(AioHTTPTestCase):
        def setUp(self):
            session = aiohttp.ClientSession()
            self.fpl = FPL(session)
    
        @unittest_run_loop
        async def test_user(self):
            user = await self.fpl.get_user("3523615")
            self.assertIsInstance(user, User)
    
            user = await self.fpl.get_user("3523615", True)
            self.assertIsInstance(user, dict)
    

    给予

    tests/test_fpl.py:20: DeprecationWarning: The object should be created from async function
      session = aiohttp.ClientSession()
      ...
    ======================================================================
    ERROR: test_user (__main__.FPLTest)
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "/home/amos/Documents/fpl/venv/lib/python3.7/site-packages/aiohttp/test_utils.py", line 477, in new_func
        return self.loop.run_until_complete(
    AttributeError: 'FPLTest' object has no attribute 'loop'
    
    ======================================================================
    ERROR: test_user (__main__.FPLTest)
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "/home/amos/Documents/fpl/venv/lib/python3.7/site-packages/aiohttp/test_utils.py", line 451, in tearDown
        self.loop.run_until_complete(self.tearDownAsync())
    AttributeError: 'FPLTest' object has no attribute 'loop'
    
    1 回复  |  直到 6 年前
        1
  •  3
  •   Samuel Colvin    6 年前

    使用PyTestand aiohttp-pytest :

    async def test_test_user(loop):
        async with aiohttp.ClientSession() as session:
             fpl = FPL(session)
             user = await fpl.get_user(3808385)
        assert isinstance(user, User)
    

    现代Python开发人员的格言:生命太短,不能使用pytest。

    您可能还希望设置一个模拟服务器来在测试期间接收HTTP请求,我没有一个简单的示例,但是可以看到一个完整的工作示例。 here .