多个异步单元测试失败,但一一运行它们会通过

Hou*_*man 7 python pytest pytest-asyncio fastapi python-3.9

我有两个单元测试,如果我一一运行它们,它们就会通过。如果我在类级别运行它们,一个通过,另一个失败response = await ac.post(并显示错误消息:RuntimeError: Event loop is closed

@pytest.mark.asyncio
async def test_successful_register_saves_expiry_to_seven_days(self):
    async with AsyncClient(app=app, base_url="http://127.0.0.1") as ac:
        response = await ac.post(
            "/register/",
            headers={},
            json={
                "device_id": "u1",
                "device_type": DeviceType.IPHONE.value,
            },
        )
        query = device.select(whereclause=device.c.id == "u1")
        d = await db.fetch_one(query)
        assert d.expires_at == datetime.utcnow().replace(
            second=0, microsecond=0
        ) + timedelta(days=7)

@pytest.mark.asyncio
async def test_successful_register_saves_device_type(self):
    async with AsyncClient(app=app, base_url="http://127.0.0.1") as ac:
        response = await ac.post(
            "/register/",
            headers={},
            json={
                "device_id": "u1",
                "device_type": DeviceType.ANDROID.value,
            },
        )
        query = device.select(whereclause=device.c.id == "u1")
        d = await db.fetch_one(query)
        assert d.type == DeviceType.ANDROID.value
Run Code Online (Sandbox Code Playgroud)

我已经尝试了几个小时了,请问我错过了什么?

Hou*_*man 19

更新(>= 0.19.0)

最新0.19.0pytest-asyncio已成为strict。您现在需要更改with@pytest.fixture中的每一个内容。conftest.py@pytest_asyncio.fixture

这些事情经常发生变化。


更新(<0.19.0)

确实已@pytest.yield_fixture被弃用。版本之前的正确方法0.19.0

@pytest.fixture(scope="session")
def event_loop(request):
    loop = asyncio.get_event_loop()
    yield loop
    loop.close()
Run Code Online (Sandbox Code Playgroud)

原答案:

我已经找到了解决方案。

conftest.py创建一个名为下的文件tests

并插入以下内容:

@pytest.yield_fixture(scope="session")
def event_loop(request):
    """Create an instance of the default event loop for each test case."""
    loop = asyncio.get_event_loop_policy().new_event_loop()
    yield loop
    loop.close()
Run Code Online (Sandbox Code Playgroud)

这将在每次测试后正确结束循环并允许运行多个测试。

  • 夹具注释具有误导性,它不是为每个测试用例创建事件循环的实例,而是仅创建一次事件循环(对于会话)并在所有测试中使用它 (2认同)