【问题标题】:How to call an async function in pytest_sessionfinish()?如何在 pytest_sessionfinish() 中调用异步函数?
【发布时间】:2022-01-06 09:20:45
【问题描述】:

我正在使用pytest-asyncio

我有以下conftest.py 文件:

import asyncio

import pytest
from database.mongo_db import mongo


@pytest.fixture(scope="session", autouse=True)
async def initialise_db():
    await mongo.connect_client()
    await mongo.drop_db()

@pytest.fixture(scope="session")
def event_loop():
    yield asyncio.new_event_loop()

initialise_db() 函数将连接到我的数据库并在运行所有测试之前清除其中的所有内容。

现在,我想关闭事件循环并在所有测试完成后关闭与我的数据库的连接。我尝试将以下函数添加到conftest.py

def pytest_sessionfinish(session, exitstatus):
    asyncio.get_event_loop().close()
    mongo.disconnect_client()

但是,这个新功能有两个问题:

  1. asyncio.get_event_loop().close() 发出警告:DeprecationWarning: There is no current event loop
  2. mongo.disconnect_client() 是一个异步函数。如果我将pytest_sessionfinish 更改为异步函数并在关闭数据库时使用await,则会收到警告:RuntimeWarning: coroutine 'pytest_sessionfinish' was never awaited,这是从 pytest 中调用的,因此除非我编辑源代码。当然,如果我不将其设为异步函数,我会收到警告:RuntimeWarning: coroutine 'disconnect_client' was never awaited

如何解决这两个问题?

【问题讨论】:

    标签: python asynchronous pytest python-asyncio pytest-asyncio


    【解决方案1】:
    1. 不要。 Pytests 管理事件循环,您不应该(也不需要)干预它。 [编辑:好的,对不起。干涉,如果你必须...例如扩大 event_loop 固定装置的范围。]

    2. 夹具应自行拆卸。只需将其定义为产量夹具:

    @pytest.fixture(scope="session")
    def event_loop():
        loop = asyncio.new_event_loop()
        yield loop
        loop.close()
    
    @pytest.fixture(scope="session", autouse=True)
    async def initialise_db():
        await mongo.connect_client()
        await mongo.drop_db()
        yield # suspended until tests are done
        await mongo.disconnect_client() # pytest calls teardown when fixture goes out of scope
    

    event_loopfixture 默认由 pytest-asyncio 提供,但可以被覆盖以更改范围或提供自定义循环。详见 pytest-asyncio readme

    【讨论】:

    • 谢谢,我理解第 1 点,但是当我使用您给出的解决方案时(使用scope="session"),我收到以下错误:ScopeMismatch: You tried to access the 'function' scoped fixture 'event_loop' with a 'session' scoped request object。目前,我可以将此夹具与默认的 function 范围一起使用,但我认为将来我必须将范围更改为 session,以便我的数据库在所有测试中保持持久化。
    • 你说得对,我忽略了范围问题。我会相应地编辑答案。
    • 也许我误解了你的评论。您在示例中使用“会话”范围自己定义了一个 event_loop 固定装置。为什么 pytest 抱怨你用“function”-scope 定义了你的事件循环?
    • 当我尝试更新的解决方案时,我收到以下警告:DeprecationWarning: There is no current event loop 这会导致我的测试失败(我认为是因为没有返回事件循环),因此我原来的解决方案使用了@987654330 @.
    • 我没有得到DeprecationWarning,因为我还在使用Python 3.8...如果您改用new_event_loop(),它是否有效?我现在不能轻易测试这个,但我不明白为什么它不应该工作。我将更新示例。
    猜你喜欢
    • 2020-03-09
    • 2020-12-20
    • 1970-01-01
    • 1970-01-01
    • 2019-01-20
    • 2018-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多