Python 为异步tornado web套接字服务器编写同步测试套件
我正试图为我的TornadoWebSocket服务器设计一个测试套件 我使用客户机来实现这一点——通过websocket连接到服务器,发送请求并期望得到某种响应 我使用python的unittest来运行我的测试,所以我不能(也不想)强制执行测试运行的顺序 这就是我的基本测试类(所有测试用例继承之后)的组织方式。(此处不相关的测井和某些部分被剥离) 我提出的方案是让这个基类在所有测试中初始化一次连接(尽管不一定是这样-如果它解决了我的问题,我很乐意为每个测试用例设置并拆除连接)。重要的是,我不希望同时打开多个连接 简单的测试用例是这样的Python 为异步tornado web套接字服务器编写同步测试套件,python,asynchronous,websocket,tornado,python-unittest,Python,Asynchronous,Websocket,Tornado,Python Unittest,我正试图为我的TornadoWebSocket服务器设计一个测试套件 我使用客户机来实现这一点——通过websocket连接到服务器,发送请求并期望得到某种响应 我使用python的unittest来运行我的测试,所以我不能(也不想)强制执行测试运行的顺序 这就是我的基本测试类(所有测试用例继承之后)的组织方式。(此处不相关的测井和某些部分被剥离) 我提出的方案是让这个基类在所有测试中初始化一次连接(尽管不一定是这样-如果它解决了我的问题,我很乐意为每个测试用例设置并拆除连接)。重要的是,我不希
class ATest(BaseTest):
@classmethod
def setUpClass(cls):
super(ATest, cls).setUpClass()
@classmethod
def tearDownClass(cls):
super(ATest, cls).tearDownClass()
def test_a(self):
saved_stdout = sys.stdout
try:
out = StringIO()
sys.stdout = out
message_sent = self.websocket.write_message(
str({'opcode': 'a_message'}})
)
output = out.getvalue().strip()
# the code below is useless
while (output is None or not len(output)):
self.log.debug("%s waiting for response." % str(inspect.stack()[0][3]))
output = out.getvalue().strip()
self.assertIn(
'a_response', output,
"Server didn't send source not a_response. Instead sent: %s" % output
)
finally:
sys.stdout = saved_stdout
它在大多数情况下运行良好,但它不是完全确定的(因此是可靠的)。由于websocket通信是异步执行的,而unittest同步执行测试,因此服务器响应(在同一websocket上接收)会与请求混淆,测试偶尔会失败
我知道它应该是基于回调的,但这并不能解决响应混合的问题。除非,否则所有测试都是在一系列回调中人工排序的(如test_1_回调中的start test_2)
Tornado提供了一种帮助同步测试的方法,但我似乎无法让它与WebSocket一起工作(Tornado.ioloop有自己的线程,您无法阻止)
我找不到一个python websocket同步客户端库,它可以与tornado服务器一起工作,并且兼容RFC6455。Pypi未能满足第二个需求
我的问题是:
from tornado.testing import AsyncHTTPTestCase, gen_test
from tornado.websocket import WebSocketHandler, websocket_connect
class MyHandler(WebSocketHandler):
""" This is the server code you're testing."""
def on_message(self, message):
# Put whatever response you want in here.
self.write_message("a_response\n")
class WebSocketTest(AsyncHTTPTestCase):
def get_app(self):
return Application([
('/', MyHandler, dict(close_future=self.close_future)),
])
@gen_test
def test_a(self):
ws = yield websocket_connect(
'ws://localhost:%d/' % self.get_http_port(),
io_loop=self.io_loop)
ws.write_message(str({'opcode': 'a_message'}}))
response = yield ws.read_message()
self.assertIn(
'a_response', response,
"Server didn't send source not a_response. Instead sent: %s" % response
)v
decorator允许您以协同程序的形式运行异步测试用例,当在tornado的ioloop中运行时,可以有效地使它们同步运行以进行测试。同时,我设法找到了一个解决方案。[ws4py](ws4py.readthedocs.org)websocket客户端为我完成了这个任务。但你的解决方案更优雅。谢谢你,先生。
from tornado.testing import AsyncHTTPTestCase, gen_test
from tornado.websocket import WebSocketHandler, websocket_connect
class MyHandler(WebSocketHandler):
""" This is the server code you're testing."""
def on_message(self, message):
# Put whatever response you want in here.
self.write_message("a_response\n")
class WebSocketTest(AsyncHTTPTestCase):
def get_app(self):
return Application([
('/', MyHandler, dict(close_future=self.close_future)),
])
@gen_test
def test_a(self):
ws = yield websocket_connect(
'ws://localhost:%d/' % self.get_http_port(),
io_loop=self.io_loop)
ws.write_message(str({'opcode': 'a_message'}}))
response = yield ws.read_message()
self.assertIn(
'a_response', response,
"Server didn't send source not a_response. Instead sent: %s" % response
)v