I recently had to rewrite our rest api, and made the switch from Flask to Cherrypy (mostly due to Python 3 compatibility). But now I'm stuck trying to write my unit tests, Flask has a really nifty built-in test client, that you can use to sent fake requests to your application (without starting a server.) I can't find any similar functionality for Cherrypy, is there such functionality, or am I stuck starting a server and doing actual requests against it?
As far as I know, CherryPy doesn't indeed provide a facility for this type of testing (no running server). But it's fairly easy to do it nonetheless (though it relies on some of the internals of CherryPy).
Here's a simple showcase:
from StringIO import StringIO
import unittest
import urllib
import cherrypy
local = cherrypy.lib.httputil.Host('127.0.0.1', 50000, "")
remote = cherrypy.lib.httputil.Host('127.0.0.1', 50001, "")
class Root(object):
@cherrypy.expose
def index(self):
return "hello world"
@cherrypy.expose
def echo(self, msg):
return msg
def setUpModule():
cherrypy.config.update({'environment': "test_suite"})
# prevent the HTTP server from ever starting
cherrypy.server.unsubscribe()
cherrypy.tree.mount(Root(), '/')
cherrypy.engine.start()
setup_module = setUpModule
def tearDownModule():
cherrypy.engine.exit()
teardown_module = tearDownModule
class BaseCherryPyTestCase(unittest.TestCase):
def webapp_request(self, path='/', method='GET', **kwargs):
headers = [('Host', '127.0.0.1')]
qs = fd = None
if method in ['POST', 'PUT']:
qs = urllib.urlencode(kwargs)
headers.append(('content-type', 'application/x-www-form-urlencoded'))
headers.append(('content-length', '%d' % len(qs)))
fd = StringIO(qs)
qs = None
elif kwargs:
qs = urllib.urlencode(kwargs)
# Get our application and run the request against it
app = cherrypy.tree.apps['']
# Let's fake the local and remote addresses
# Let's also use a non-secure scheme: 'http'
request, response = app.get_serving(local, remote, 'http', 'HTTP/1.1')
try:
response = request.run(method, path, qs, 'HTTP/1.1', headers, fd)
finally:
if fd:
fd.close()
fd = None
if response.output_status.startswith('500'):
print response.body
raise AssertionError("Unexpected error")
# collapse the response into a bytestring
response.collapse_body()
return response
class TestCherryPyApp(BaseCherryPyTestCase):
def test_index(self):
response = self.webapp_request('/')
self.assertEqual(response.output_status, '200 OK')
# response body is wrapped into a list internally by CherryPy
self.assertEqual(response.body, ['hello world'])
def test_echo(self):
response = self.webapp_request('/echo', msg="hey there")
self.assertEqual(response.output_status, '200 OK')
self.assertEqual(response.body, ["hey there"])
response = self.webapp_request('/echo', method='POST', msg="hey there")
self.assertEqual(response.output_status, '200 OK')
self.assertEqual(response.body, ["hey there"])
if __name__ == '__main__':
unittest.main()
Edit, I've extended this answer as a CherryPy recipe.
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