How to write functions to be called from within a @tornado.testing.gen_test?
python, tornado
Solution
You should use `@gen.coroutine` on asynchronous functions to be called by `@gen_test` methods, just like in non-test code. `@gen_test` is an adapter for your top-level test function that makes it possible to use asynchronous code in the synchronous unittest interface.
@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
In Python 3.3+, you can use `return response` instead of `raise gen.Return(response)`. You can even omit the `@gen.coroutine` if you use `yield from` at the call site.
Problem
So I've got some code I want to test, and I'm encountering what looks like a pretty horrible side effect of the yield generator-based nature of `@tornado.testing.gen_test`'s expected input tests: ``` 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 ``` The problem is that I can't return a value from a generator, so my natural instinct here is wrong. Furthermore, I can't do this: ``` 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 ``` Because then I encounter the error: ``` AttributeError: 'NoneType' object has no attribute 'write_message' ``` Obviously, I can include the entire test generation code in the test, but that's really ugly, hard to maintain, etc. Does this testing pattern really make indirection so difficult?