建议的测试模式需要应用程序代码的样板重复,并且不显示直接测试应用程序。
https://docs.aiohttp.org/en/stable/testing.html#pytest
我应该能够将我的应用程序模块直接传递给test_client
来测试我的应用程序。
文档显示了在每次测试之前从处理程序动态构建应用程序。 第一次将真实的app
直接传递给test_client
工作正常,然后失败并显示“RuntimeError: web.Application instance initialized with different loop”。
# handler.py
async def foo():
return 'foo'
# app.py
from aiohttp import web
from .handler import foo
app = web.Application()
app.add_routes([web.get('/foo/', foo)])
# test.py
from .app import app
async def test_foo_status(test_client):
response = await client.get('/foo/')
assert response.status == 200
async def test_foo_body(test_client):
response = await client.get('/foo/')
body = await response.text()
assert body == 'foo'
我暂时通过查看源代码并确定错误原因来解决这个问题。
if self._loop is not None and self._loop is not loop:
raise RuntimeError(
"web.Application instance initialized with different loop")
https://github.com/aio-libs/aiohttp/blob/e561eaa/aiohttp/web_app.py#L134
我不清楚为什么需要这段代码。 我在 git 历史中找不到任何上下文。 在我的测试清理方法中设置app._loop = None
似乎可以避免该问题而没有任何负面影响。 这段代码真的有必要吗? 此修复程序是否可以集成到test_client
?
Application
是一个有状态的对象,它应该为单元测试套件中的每个测试重新创建。
应用程序的生命周期应该比事件循环的生命周期短。
提示:将app.app
替换async def app.make_app()
协程,每次调用都会返回一个新的应用程序。
将def make_app()
到app.py
? 那讲得通。
FWIW 龙卷风在他们的第一个例子中推广了make_app()
模式。 我不认为在测试文件中模拟应用程序是文档推广的好模式。
老实说,我不认为嘲笑任何aiohttp
对象是一个好模式
由于关闭后没有任何近期活动,因此该线程已自动锁定。 请打开 [新问题] 以获取相关错误。
如果您觉得本次讨论中有重要观点,请将这些摘录包含在该 [新问题] 中。
最有用的评论
Application
是一个有状态的对象,它应该为单元测试套件中的每个测试重新创建。应用程序的生命周期应该比事件循环的生命周期短。
提示:将
app.app
替换async def app.make_app()
协程,每次调用都会返回一个新的应用程序。