Search code examples
pythonunit-testingtestingtornado

Testing Tornado app for 4xx status code


Consider the following Tornado (v 4.0.2) application, which is a little bit modified version of official hello world example:

import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.set_status(400)
        self.write("Hello, world")

application = tornado.web.Application([
    (r"/", MainHandler),
])

if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

As you can see, the only difference here is set_status call in MainHandler. Now, I save this code into app.py, then I open tests.py and I put there this simple unit test:

import tornado.ioloop
from tornado.httpclient import HTTPRequest
from tornado.testing import AsyncHTTPTestCase, gen_test

from app import application

class SimpleTest(AsyncHTTPTestCase):
    def get_app(self):
        return application

    def get_new_ioloop(self):
        return tornado.ioloop.IOLoop.instance()

    @gen_test
    def test_bad_request(self):
        request = HTTPRequest(url=self.get_url('/'))
        response = yield self.http_client.fetch(request)
        self.assertEqual(response.code, 400)

When I run this test with python -m tornado.test.runtests tests I get the following result:

E
======================================================================
ERROR: test_bad_request (tests.SimpleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/tornado/testing.py", line 118, in __call__
    result = self.orig_method(*args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/tornado/testing.py", line 494, in post_coroutine
    timeout=timeout)
  File "/usr/local/lib/python2.7/dist-packages/tornado/ioloop.py", line 418, in run_sync
    return future_cell[0].result()
  File "/usr/local/lib/python2.7/dist-packages/tornado/concurrent.py", line 109, in result
    raise_exc_info(self._exc_info)
  File "/usr/local/lib/python2.7/dist-packages/tornado/gen.py", line 631, in run
    yielded = self.gen.throw(*sys.exc_info())
  File "tests.py", line 18, in test_bad_request
    response = yield self.http_client.fetch(request)
  File "/usr/local/lib/python2.7/dist-packages/tornado/gen.py", line 628, in run
    value = future.result()
  File "/usr/local/lib/python2.7/dist-packages/tornado/concurrent.py", line 111, in result
    raise self._exception
HTTPError: HTTP 400: Bad Request

----------------------------------------------------------------------
Ran 1 test in 0.022s

FAILED (errors=1)
[E 140929 12:55:59 testing:687] FAIL

Obviously this is correct, because the handler sets 400 status code. But how can I test my application for such case? I think 4xx codes are useful, so I don't want to give them up. However I'm new to Tornado and I wasn't able to find a way to test them. Is there any?


Solution

  • Try this:

        @gen_test
        def test_bad_request(self):
            request = HTTPRequest(url=self.get_url('/'))
            with self.assertRaises(tornado.httpclient.HTTPError) as context:
                yield self.http_client.fetch(request)
    
            self.assertEqual(context.exception.code, 400)
    

    See the documentation for assertRaises.