You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在pytest-twisted装饰的测试函数中正确使用pytest-asyncio的aiohttp_client fixture?

如何在pytest-twisted装饰的测试函数中正确使用pytest-asyncio的aiohttp_client fixture?

问题背景

你遇到的问题本质是Twisted的AsyncioReactor和pytest-asyncio维护的事件循环没有共享,导致两者的循环生命周期不一致,最终触发了RuntimeError: Event loop is closed错误。从你提供的最小复现代码和配置来看,核心冲突点在于:测试函数用@pytest_twisted.ensureDeferred装饰(依赖Twisted的反应器循环),但aiohttp_client fixture默认使用function级别的独立循环,两者循环实例不统一,最终导致循环被提前关闭。

解决方案

核心思路是让Twisted和aiohttp强制使用同一个全局共享的事件循环,并且统一循环的生命周期为整个测试会话。具体步骤如下:

1. 调整pytest配置

修改你的pyproject.toml(或pytest.ini),把循环范围设为session,确保整个测试过程中只有一个循环实例:

[tool.pytest.ini_options]
addopts = [
    "--reactor=asyncio",
]
asyncio_mode = "strict"
asyncio_default_fixture_loop_scope = "session"

2. 编写全局绑定反应器的Fixture

写一个自动执行的session级Fixture,把Twisted的AsyncioReactor绑定到pytest-asyncio提供的全局循环上,避免Twisted自行创建新循环:

import pytest
from twisted.internet import asyncioreactor

@pytest.fixture(scope="session", autouse=True)
def setup_shared_reactor(event_loop):
    # 将Twisted反应器绑定到pytest-asyncio的session级循环
    asyncioreactor.install(event_loop)
    reactor = asyncioreactor.AsyncioSelectorReactor(event_loop)
    
    # 测试会话结束后停止反应器
    yield reactor
    reactor.stop()

3. 测试代码保持原有结构即可

你的最小测试代码不需要大改,现在可以正常运行:

from pytest_twisted import ensureDeferred
from aiohttp import web

@ensureDeferred
async def test_minimal(aiohttp_client):
    app = web.Application()
    client = await aiohttp_client(app)
    
    # 示例测试逻辑:请求根路径,预期404(因为未配置路由)
    resp = await client.get('/')
    assert resp.status == 404

为什么这样能解决问题?

  • 共享循环:把循环范围设为session后,pytest-asyncio会在整个测试会话中维护同一个事件循环,不会在每个测试结束后就关闭它
  • 绑定反应器:手动让Twisted的AsyncioReactor使用这个共享循环,避免了Twisted创建独立循环导致的冲突
  • 生命周期统一:反应器和循环的生命周期都绑定到测试会话,不会出现循环提前关闭的情况

额外注意事项

  • 不要在测试或Fixture中手动创建/关闭事件循环,完全交给pytest-asyncio管理
  • 如果你的自定义Fixture依赖aiohttp或Twisted,记得把它们的scope也设为session(如果业务逻辑允许),避免重复初始化
  • 如果之前尝试过asyncio_mode="auto",其实也可以使用,但strict模式更严谨,能帮你提前发现循环使用的问题

备注:内容来源于stack exchange,提问作者wRAR

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 10:43:01