Unittesting cherrypy webapp

后端 未结 3 1283
囚心锁ツ
囚心锁ツ 2021-02-02 18:16

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, Flas

3条回答
  •  臣服心动
    2021-02-02 18:51

    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.

提交回复
热议问题