2013-01-10 59 views
10

我最近不得不重寫我們的其餘api,並將Flask切換到Cherrypy(主要歸功於Python 3的兼容性)。但是現在我試圖寫我的單元測試,Flask有一個非常漂亮的內置測試客戶端,您可以使用它向您的應用程序發送虛假請求(無需啓動服務器)。我找不到任何類似的功能對於Cherrypy,有沒有這樣的功能,還是我堅持啓動一個服務器,並針對它做實際的請求?單元測試cherrypy webapp

回答

18

據我所知,CherryPy確實沒有提供這種類型的測試(沒有運行服務器)的設施。但儘管如此,它仍然很容易(儘管它依賴於CherryPy的一些內部)。

這裏有一個簡單的展示:

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() 

編輯,我已經延長這個答案作爲CherryPy recipe

+0

謝謝,今天要去這個給一試。 – Blubber

+0

工程就像一個魅力,再次感謝:)。 – Blubber

+0

@Sylvain:'@ cherrypy.tools.json_in()'支持有什麼特別需要?測試用例中的'cherrypy.request.json'導致'AttributeError:'Request'對象沒有屬性'json'' – user1338062

2

看來,有一種替代方法來執行單元測試。 我剛剛發現並檢查以下配方,可以在cherrypy 3.5下正常工作。

http://docs.cherrypy.org/en/latest/advanced.html#testing-your-application

import cherrypy 

    from cherrypy.test import helper 

    class SimpleCPTest(helper.CPWebCase): 
     def setup_server(): 
      class Root(object): 
       @cherrypy.expose 
       def echo(self, message): 
        return message 

      cherrypy.tree.mount(Root()) 
     setup_server = staticmethod(setup_server) 

     def test_message_should_be_returned_as_is(self): 
      self.getPage("/echo?message=Hello%20world") 
      self.assertStatus('200 OK') 
      self.assertHeader('Content-Type', 'text/html;charset=utf-8') 
      self.assertBody('Hello world') 

     def test_non_utf8_message_will_fail(self): 
      """ 
      CherryPy defaults to decode the query-string 
      using UTF-8, trying to send a query-string with 
      a different encoding will raise a 404 since 
      it considers it's a different URL. 
      """ 
      self.getPage("/echo?message=A+bient%F4t", 
         headers=[ 
          ('Accept-Charset', 'ISO-8859-1,utf-8'), 
          ('Content-Type', 'text/html;charset=ISO-8859-1') 
         ] 
      ) 
      self.assertStatus('404 Not Found') 
+0

這肯定CherryPy測試是如何在內部編寫的。但是這意味着啓動一臺實際的服務器。這是自動的,但我的配方試圖顯示你可以測試你的處理程序,而無需運行服務器。你的迴應並不是不正確的,只是在我說的集成方面多一點。 –