gpt4 book ai didi

python - 使用 AsyncIOMainLoop 测试 Tornado 应用程序时出现 AssertionError "assert not IOLoop.initialized()"

转载 作者:太空宇宙 更新时间:2023-11-04 04:49:34 24 4
gpt4 key购买 nike

我在为使用异步事件循环的现有 Tornado 应用程序编写 AsyncHTTPTestCase 测试时遇到了一些问题。在这里,我准备了可以重现问题的短模型:

app.py

from tornado.platform.asyncio import AsyncIOMainLoop
import asyncio
import tornado.web


class MainHandler(tornado.web.RequestHandler):
async def get(self, *args, **kwargs):
self.write("200 OK")

async def post(self, *args, **kwargs):
self.write("201 OK")

def make_app():
AsyncIOMainLoop().install() # here is how to asyncio loop installed in app I already have
return tornado.web.Application([
(r"/", MainHandler),
], debug=True)

def start_app():
app = make_app()
app.listen(8888)
loop = asyncio.get_event_loop()
loop.set_debug(True)
loop.run_forever()

开始.py

#!/usr/bin/env python3
import app

if __name__ == "__main__":
app.start_app()

test_app.py

import json
from tornado.testing import AsyncHTTPTestCase

import app

class TestHelloApp(AsyncHTTPTestCase):
def get_app(self):
return app.make_app()

def test_get(self):
response = self.fetch('/')
self.assertEqual(response.code, 200)
self.assertEqual(response.body.decode(), '200 OK')

def test_post(self):
response = self.fetch('/', method="POST",
body=json.dumps({"key": "value"}))
self.assertEqual(response.code, 200)
self.assertEqual(response.body.decode(), '201 OK')

使用这种安装异步循环应用程序的方法可以正常工作(我的意思是我可以执行请求并且我正在收到响应),但是像这样的测试失败并出现错误:

======================================================================
FAIL: test_post (test_app.TestHelloApp)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/biceps/work/torn/.venv/lib/python3.6/site-packages/tornado/testing.py", line 380, in setUp
self._app = self.get_app()
File "/home/biceps/work/torn/test_app.py", line 8, in get_app
return app.make_app()
File "/home/biceps/work/torn/app.py", line 14, in make_app
tornado.platform.asyncio.AsyncIOMainLoop().install()
File "/home/biceps/work/torn/.venv/lib/python3.6/site-packages/tornado/ioloop.py", line 181, in install
assert not IOLoop.initialized()
AssertionError

----------------------------------------------------------------------
Ran 2 tests in 0.006s

FAILED (failures=1)

似乎由 AsyncIOMainLoop().install() 命令安装的循环在测试之间没有停止,第一次测试正常通过,但第二次总是失败。

当我将 AsyncIOMainLoop().install() 移动到 start_app() 方法时 - 测试顺利通过,但我担心在测试期间我使用一个事件循环,但在实际运行的应用程序中我使用异步循环。

因此,针对该代码测试通过 OK:

from tornado.platform.asyncio import AsyncIOMainLoop
import asyncio
import tornado.web


class MainHandler(tornado.web.RequestHandler):
async def get(self, *args, **kwargs):
self.write("200 OK")

async def post(self, *args, **kwargs):
self.write("201 OK")

def make_app():
return tornado.web.Application([
(r"/", MainHandler),
], debug=True)

def start_app():
AsyncIOMainLoop().install()
app = make_app()
app.listen(8888)
loop = asyncio.get_event_loop()
loop.set_debug(True)
loop.run_forever()

问:我的问题是 - 如何在该用例中正确编写测试?当 Tornado 应用程序使用 AsyncIOMainLoop 时,如何使用 AsyncHTTPTestCase 编写测试?我决定将 AsyncIOMainLoop().install() 放入 start_app() 而不是 make_app() 函数中是否正确?

附言我已将 self.io_loop.clear_instance() 添加到 tearDown() - 它看起来可能很脏,但适用于从 make_app() 代码调用 AsyncIOMainLoop().install() 的情况。

    def tearDown(self):
self.io_loop.clear_instance()
super().tearDown()

最佳答案

根据文档,我需要在启动应用程序之前安装 AsyncIOMainLoop,而不是在我制作应用程序时。 documentation

from tornado.platform.asyncio import AsyncIOMainLoop
import asyncio
AsyncIOMainLoop().install()
asyncio.get_event_loop().run_forever()

所以现在我确定正确的方法是使用 AsyncIOMainLoop 安装到 start_app() 代码中。

所以现在我的模式代码如下所示:

web1.py

class MainHandler(tornado.web.RequestHandler):
async def get(self, *args, **kwargs):
await asyncio.sleep(1)
return self.write("OK")

async def post(self, *args, **kwargs):
await asyncio.sleep(1)
return self.write("OK")

def make_app():
return tornado.web.Application([(r"/", MainHandler),],
debug=False)

def start_app():
from tornado.platform.asyncio import AsyncIOMainLoop
import asyncio
AsyncIOMainLoop().install()
app = make_app()
app.listen(8888)
asyncio.get_event_loop().run_forever()


if __name__ == "__main__":
start_app()

test_app.py

from tornado.testing import AsyncHTTPTestCase

import web1

class TestTornadoAppBase(AsyncHTTPTestCase):
def get_app(self):
return web1.make_app()

def get_new_ioloop(self):
"""
Needed to make sure that I can also run asyncio based callbacks in my tests
"""
io_loop = tornado.platform.asyncio.AsyncIOLoop()
asyncio.set_event_loop(io_loop.asyncio_loop)
return io_loop

class TestGET(TestTornadoAppBase):
def test_root_get_method(self):
response = self.fetch("/")
self.assertEqual(response.code, 200)
self.assertEqual(response.body.decode(), 'OK')

def test_root_post_method(self):
response = self.fetch("/", method="POST", body="{}")
self.assertEqual(response.code, 200)
self.assertEqual(response.body.decode(), 'OK')

此模式也适用,并且在测试期间使用 AsyncIOMainLoop。所以我可以使用那些使用异步循环的库。例如,在我的示例中有 asyncio.sleep()。

关于python - 使用 AsyncIOMainLoop 测试 Tornado 应用程序时出现 AssertionError "assert not IOLoop.initialized()",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48693132/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com