I was wondering if Unittest or Pytest would be enough, but I decided to check out Tornado's Testing Framework. I found that it would be helpful to start Tornado HTTPServer in a test script and call it Tornado Mock Server, or to run and test it, so I decided to implement and test it immediately. .. I decided to put together a sample code as a memorandum at that time. Since I tried 2.4 series this time, the information may be a little out of date, but the basics should not change.
test_tornadoweb.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#Import required modules
import tornado.testing
import tornado.web
import mock
import urllib
from tornado.httpclient import HTTPRequest
#Helper function
def urlencode_request_params(**params):
return urllib.urlencode(
dict(
[k, v.encode("utf-8") if isinstance(v, unicode) else v]
for k, v in params.items()
)
)
def prepare_kwargs(**params):
kwargs = dict(
body=urlencode_request_params(**params),
)
return kwargs
#Sample handler
class ProfileHandler(tornado.web.RequestHandler):
"""To try get method
"""
def get(self):
user_id = self.get_argument("user_id")
if user_id != "tornadoweb":
raise tornado.web.HTTPError(404)
self.finish("ok")
class AccountHandler(tornado.web.RequestHandler):
"""tornado.web.Tests when using authenticated decorators
Things to do
"""
@tornado.web.authenticated
def get(self):
self.finish("I'm " + self.current_user)
@tornado.web.authenticated
def post(self):
bio = self.get_argument("bio")
self.finish("{error:0, msg:{bio:%s}}" % bio)
class TestSample(tornado.testing.AsyncHTTPTestCase):
"""Inherit AsyncHTTPTestCase and start HTTP Server
"""
def setUp(self):
"""Find a free port in the super class get_Registered in app
Starting Tornado with handler as Application
self.http_client is prepared and self.http_client.fetch()
Can also be used
"""
super(TestSample, self).setUp()
def get_httpserver_options(self):
"""You can also specify options when starting the HTTP server
"""
return {}
def get_app(self):
"""Set the routing of the application handler.
If you have application settings, you can specify them here.
"""
application_settings = dict()
return tornado.web.Application([
("/profile", ProfileHandler),
("/account", AccountHandler),
("/account/update", AccountHandler),
], **application_settings)
def test_httprequest_sample(self):
"""You can also make a request directly using HTTPRequest, so a trial test
"""
kwargs = dict()
test_url = 'http://snapdish.co'
request = HTTPRequest(test_url, **kwargs)
self.http_client.fetch(request, self.stop, **kwargs)
response = self.wait()
self.assertEqual(response.code, 200)
def test_profile(self):
"""Test if you can get the profile normally
"""
kwargs = dict(
user_id="tornadoweb"
)
path = "%s?%s" % ("/profile", urlencode_request_params(**kwargs))
response = self.fetch(path)
self.assertEqual(response.code, 200)
self.assertEqual(response.body, "ok")
def test_profile_404(self):
"""Test if profile request is returning 404 if wrong
"""
kwargs = dict(
user_id="tornadoweb?"
)
path = "%s?%s" % ("/profile", urlencode_request_params(**kwargs))
response = self.fetch(path)
self.assertEqual(response.code, 404)
def test_account(self):
"""When using authenticated decorators, use mock
current_user needs to be modified"""
with mock.patch.object(AccountHandler, 'get_current_user') as m:
m.return_value = "tornadoweb"
path = "/account"
response = self.fetch(path)
self.assertEqual(response.code, 200)
self.assertEqual(response.body, "I'm tornadoweb")
def test_account_update(self):
"""When using authenticated decorators, use mock
current_user needs to be modified"""
with mock.patch.object(AccountHandler, 'get_current_user') as m:
m.return_value = "tornadoweb"
bio = "tornadoweb bio"
params = dict(bio=bio)
response = self.fetch("/account/update",
method="POST",
follow_redirects=False,
body=urlencode_request_params(**params))
self.assertEqual(response.code, 200)
self.assertEqual(response.body, "{error:0, msg:{bio:%s}}" % bio)
setUp() It works by searching for a free port, preparing http_client, setting an application handler, and starting Tornado HTTPServer. get_app() It is implemented on the subclass side, and specifies the handler you want to test and its path. You can also set up the application here. Specify template_path etc. fetch(path, **kwargs)
self.http_client.In a wrapper for fetch and self inside.get_url(path)I am doing. self.get_url(path)Will use the path passed as an argument to generate a url to the HTTPServer started in this test and execute the request. When you want to make a complicated request, self.http_client.fetch(request, self.stop, **kwargs)Handle requests directly using. At that time, the response is self.wait()To get using.
## tornado.web.authenticated decorators are not supported
It seems that there is no choice but to cheat using mock or cheat cookies. You can also do it using HTTPRequest, so you can do various things depending on the implementation.
## Command line execution
Specify the module name (file name) as follows and execute.
```bash
$ python -m tornado.test.runtests test_tornadoweb
https://github.com/tornadoweb/tornado/tree/master/tornado/test http://www.tornadoweb.org/en/branch2.4/testing.html
Recommended Posts