所以我有一些我想要测试的代码,而且我遇到了@tornado.testing.gen_test
预期输入测试基于yield generator的性质的非常可怕的副作用:
class GameTest(tornado.testing.AsyncHTTPTestCase):
def new_game(self):
ws = yield websocket_connect('address')
ws.write_message('new_game')
response = yield ws.read_message()
# I want to say:
# return response
@tornado.testing.gen_test
def test_new_game(self):
response = self.new_game()
# do some testing
问题在于我无法从生成器返回值,因此我的天生本能是错误的。此外,我不能这样做:
class GameTest(tornado.testing.AsyncHTTPTestCase):
def new_game(self):
ws = yield websocket_connect('address')
ws.write_message('new_game')
response = yield ws.read_message()
yield response, True
@tornado.testing.gen_test
def test_new_game(self):
for i in self.new_game():
if isinstance(i, tuple):
response, success = i
break
# do some testing
因为那时我遇到了错误:
AttributeError: 'NoneType' object has no attribute 'write_message'
显然,我可以在测试中包含整个测试生成代码,但这真的很难看,难以维护等等。这种测试模式真的让间接这么难吗?
答案 0 :(得分:5)
您应该使用@gen.coroutine
在@gen_test
方法调用异步函数,就像在非测试代码中一样。 @gen_test
是顶级测试函数的适配器,可以在同步unittest接口中使用异步代码。
@gen.coroutine
def new_game(self):
ws = yield websocket_connect('address')
ws.write_message('new_game')
response = yield ws.read_message()
raise gen.Return(response)
@tornado.testing.gen_test
def test_new_game(self):
response = yield self.new_game()
# do some testing
在Python 3.3+中,您可以使用return response
代替raise gen.Return(response)
。如果您在呼叫站点使用@gen.coroutine
,则甚至可以省略yield from
。