CherryPy is a great way to write simple http backends, but there is a part of it that I do not like very much. While there is a documented way of setting up integration tests, it did not work well for me for a couple of reasons. Mostly, I found it hard to integrate with the rest of the test suite, which was using unittest and not py.test. Failing tests would apparently “hang” when launched from the PyCharm test explorer. It turned out the tests were getting stuck in interactive mode for failing assertions, a setting which can be turned off by an environment variable. Also, the “requests” looked kind of cumbersome. So I figured out how to do the tests with the fantastic requests library instead, which also allowed me to keep using unittest and have them run beautifully from within my test explorer.
The key is to start the CherryPy server for the tests in the background and gracefully shut it down once a test is finished. This can be done quite beautifully with the contextmanager decorator:
from contextlib import contextmanager @contextmanager def run_server(): cherrypy.engine.start() cherrypy.engine.wait(cherrypy.engine.states.STARTED) yield cherrypy.engine.exit() cherrypy.engine.block()
This allows us to conviniently wrap the code that does requests to the server. The first part initiates the CherryPy start-up and then waits until that has completed. The yield is where the requests happen later. After that, we initiate a shut-down and block until that has completed.
Similar to the “official way”, let’s suppose we want to test a simple “echo” Application that simply feeds a request back at the user:
class Echo(object): @cherrypy.expose def echo(self, message): return message
Now we can write a test with whatever framework we want to use:
class TestEcho(unittest.TestCase): def test_echo(self): cherrypy.tree.mount(Echo()) with run_server(): url = "http://127.0.0.1:8080/echo" params = {'message': 'secret'} r = requests.get(url, params=params) self.assertEqual(r.status_code, 200) self.assertEqual(r.content, "secret")
Now that feels a lot nicer than the official test API!
Why don’t you just use their supplied ‘helper.CPWebCase’ for unit testing?
See the first paragraph!