I want to try to write some code following TDD practice. I want to create simple app based on python's tornado framework. I was looking through the internet how people write tests for tornado and found something like this:
class TestSomeHandler(AsyncHTTPTestCase):
def test_success(self):
response = self.fetch('/something')
self.assertEqual(response.code, 200)
Correct me if I'm wrong but it looks more like integration tests. Instead of it I'm trying to write simple unit test for some dummy handler. For example such one:
class SomeHandler(BaseHandler):
@gen.coroutine
def get(self):
try:
from_date = self.get_query_argument("from", default=None)
datetime.datetime.strptime(from_date, '%Y-%m-%d')
except ValueError:
raise ValueError("Incorrect argument value for from_date = %s, should be YYYY-MM-DD" % from_date)
And test would look like:
class TestSomeHandler(AsyncHTTPTestCase):
def test_no_from_date_param(self):
handler = SomeHandler()
with self.assertRaises(ValueError):
handler.get()
I know I miss at get()
application and request. Not handled yet how to create them.
But my question is, do people write tests for tornado like in first example or somebody calls handlers inside of app? What pattern to follow? It would be nice if somebody have relevant code to share.
The command to run the tests is python -m unittest filename.py . In our case, the command to run the tests is python -m unittest test_utils.py .
The pattern with AsyncHTTPTestCase
is used mostly because, it makes all the request stuff for you. Of course one can also use AsyncTestCase
and handle it manually.
AsyncTestCase example. Since it will be testing get
method that is coroutine, we will use gen_test
to make it a bit simpler. RequestHandler
requires Application
and HTTPRequest
objects. Because we are not relaying of app's settings, ui_methods, etc. Application
is a simple mock.
from tornado.testing import AsyncTestCase, gen_test
from tornado.web import Application
from tornado.httpserver import HTTPRequest
from unittest.mock import Mock
class TestSomeHandler(AsyncTestCase):
@gen_test
def test_no_from_date_param(self):
mock_application = Mock(spec=Application)
payload_request = HTTPRequest(
method='GET', uri='/test', headers=None, body=None
)
handler = SomeHandler(mock_application, payload_request)
with self.assertRaises(ValueError):
yield handler.get()
IMHO it is up to you which pattern to use. I choose AsyncHTTPTestCase
for http-verb methods (get, post and so on), because:
Of course rest of handler's methods tested with AsyncTestCase
.
AsyncHTTPTestCase
is designed for tests like your first example, using self.fetch
instead of instantiating Handlers directly.
RequestHandler
is not designed to be instantiated by hand without the use of an Application
, so if you have pieces of functionality that you would prefer to test without the full HTTP stack, this code should generally be in static functions or non-RequestHandler
classes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With