【问题标题】:How to fetch a record from db asynchronously while unit testing?单元测试时如何从数据库异步获取记录?
【发布时间】:2021-02-02 21:41:18
【问题描述】:

在这个单元测试中,我想检查设备是否已经创建,并且到期日期是未来 7 天。

database.py

import databases
database = databases.Database(settings.sqlalchemy_database_uri)

单元测试:

from database.database import database

def test_successful_register_expiry_set_to_seven_days():
    response = client.post(
        "/register/",
        headers={},
        json={"device_id": "u1"},
    )
    assert response.status_code == 201
    query = device.select(whereclause=device.c.id == "u1")
    d = database.fetch_one(query)
    assert d.expires_at == datetime.utcnow().replace(microsecond=0) + timedelta(days=7)

因为d 是一个协程对象,所以它会失败并显示以下消息:

AttributeError: 'coroutine' object has no attribute 'expires_at'

我不能在单元测试中使用await

d = await database.fetch_one(query)

请问我错过了什么?

【问题讨论】:

    标签: python sqlalchemy fastapi


    【解决方案1】:

    它永远不会被等待,您的代码会在信号量进入调度程序之前返回协程。

    如果您使用的是异步驱动程序,则需要等待它。有什么解决方法吗?是的。

    您可以使用asyncio.run(awaitable) 在事件循环中运行协程。

    import asyncio
    
    d = asyncio.run(database.fetch_one(query))
    

    如果您有一个当前正在运行的事件循环,您可能希望使用该事件循环。您可以通过asyncio.get_event_loop() 来实现,它将在运行循环中运行该函数。

    import asyncio
    
    asyncio.get_event_loop().run_until_complete(database.fetch_one(query))
    

    你也可以使用@pytest.mark.asyncio装饰器(见documentation)。

    @pytest.mark.asyncio
    async def dummy():
        await some_awaitable()
    

    【讨论】:

    • 很遗憾我收到了这个错误:RuntimeError: Task <Task pending name='Task-4' coro=<Database.fetch_one() running at /Users/houmie/.pyenv/versions/v391/lib/python3.9/site-packages/databases/core.py:146> cb=[_run_until_complete_cb() at /Users/houmie/.pyenv/versions/3.9.1/lib/python3.9/asyncio/base_events.py:184]> got Future <Future pending> attached to a different loop
    • 嗯,我想数据库会创建事件循环并尝试在其中执行。您可以尝试获取运行循环并使用它吗? asyncio.get_event_loop().run_until_complete(database.fetch_one(query))。如果不行,也可以试试pytest.mark_asyncio
    • @pytest.mark.asyncio 仍然抛出 RuntimeError: This event loop is already running。但另一个解决方案奏效了。您可能想更新您的答案。谢谢(如果您知道如何使用@pytest.mark.asyncio 进一步简化它,我想知道。:)
    • 我在文档中找到了。是的,它有效! fastapi.tiangolo.com/advanced/async-tests/#example
    • 太棒了!我很高兴两者都工作。我将使用替代解决方案更新答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-08
    • 1970-01-01
    • 1970-01-01
    • 2012-04-14
    • 1970-01-01
    • 1970-01-01
    • 2013-04-13
    相关资源
    最近更新 更多