如何不使用已弃用类测试tornado.web.RequestHandler子类
Tornado 6.2+ 测试RequestHandler的正确方式
问题1:实例化RequestHandler时的supports_http_1_1错误
你用错了请求对象!tornado.web.RequestHandler需要的是服务端请求对象tornado.httputil.HTTPServerRequest,而不是客户端用的tornado.httpclient.HTTPRequest——这俩是完全不同的类,后者没有supports_http_1_1属性,所以才会报错。
正确的实例化代码示例:
import tornado.web import tornado.httputil # 自定义你的RequestHandler子类 class MyHandler(tornado.web.RequestHandler): async def post(self): self.write({"status": "ok"}) # 创建Application实例 app = tornado.web.Application([(r"/", MyHandler)]) # 构造服务端请求对象 request = tornado.httputil.HTTPServerRequest( method="POST", uri="/", headers=tornado.httputil.HTTPHeaders(), body=None ) # 实例化Handler handler = MyHandler(app, request) # 现在可以调用handler的方法测试了,比如手动触发post方法 import asyncio asyncio.run(handler.post()) print(handler._write_buffer) # 查看输出内容
问题2:使用unittest.IsolatedAsyncioTestCase的原因和方法
为什么要用它?
Tornado 6.2弃用了旧的AsyncTestCase系列,官方推荐用Python标准库的unittest.IsolatedAsyncioTestCase,核心原因是:
- 它是Python官方提供的异步测试工具,不需要依赖Tornado自己的事件循环管理逻辑
- 支持直接写
async def的测试方法,自动处理事件循环的创建和销毁,避免循环复用的问题
具体用法示例
下面是一个完整的测试用例,测试自定义Handler的异步方法:
import unittest import tornado.web import tornado.httputil class MyHandler(tornado.web.RequestHandler): async def get(self): name = self.get_query_argument("name", default="guest") self.write({"message": f"Hello, {name}!"}) class TestMyHandler(unittest.IsolatedAsyncioTestCase): async def test_get_handler(self): # 创建Application和请求对象 app = tornado.web.Application([(r"/", MyHandler)]) # 构造带查询参数的请求 request = tornado.httputil.HTTPServerRequest( method="GET", uri="/?name=Alice", headers=tornado.httputil.HTTPHeaders(), ) # 实例化Handler handler = MyHandler(app, request) # 执行get方法 await handler.get() # 断言输出结果 self.assertEqual(handler._write_buffer[0].decode(), '{"message": "Hello, Alice!"}') if __name__ == "__main__": unittest.main()
如果要测试HTTP接口的完整流程(模拟请求整个应用),可以结合tornado.testing.AsyncHTTPClient在IsolatedAsyncioTestCase里使用:
import unittest import tornado.web from tornado.httpclient import AsyncHTTPClient class MyHandler(tornado.web.RequestHandler): async def post(self): data = self.get_body_argument("data") self.set_status(200) self.write({"received": data}) class TestMyHandlerHTTP(unittest.IsolatedAsyncioTestCase): async def test_http_post(self): app = tornado.web.Application([(r"/", MyHandler)]) # 监听一个随机端口 app.listen(8888) client = AsyncHTTPClient() # 发送POST请求 response = await client.fetch( "http://localhost:8888/", method="POST", body="data=test_content" ) # 断言响应 self.assertEqual(response.code, 200) self.assertEqual(response.body.decode(), '{"received": "test_content"}') if __name__ == "__main__": unittest.main()
内容的提问来源于stack exchange,提问作者AmagicalFishy
相关产品推荐
相关产品推荐

