Testing CherryPy 3 Application with Twill and Nose

I’ve been working on a CherryPy application for a few days, and wanted to write some tests. Surprisingly I could not find any tutorials or documentation on how I should test a CherryPy application. Unfortunately I also missed the last section on CherryPy Testing page; why is CherryPy application testing added as an afterthought? Wouldn’t it make more sense to start the testing section on how people can write tests for their CherryPy applications, rather than first explaining how to test CherryPy itself? Of well, at least I learned something new…

Since I got tests working with Twill first I decided to document my experience, and switch to the CherryPy way later if it makes more sense. The CherryPy Essentials book apparently has a section on testing, so reading that would probably clarify a lot of things.

There is a brief tutorial on how to test CherryPy 2 application with twill, but the instructions need some tweaking to work with CherryPy 3.

On Ubuntu 8.04 I first created a virtualenv 1.3.1 without site packages. I am running Python 2.5.2, and I have the following packages installed in the virtualenv: setuptools 0.6c9, CherryPy 3.1.2, twill 0.9 and nose 0.11.1. The additional packages were installed with easy_install.

My directory structure is as follows:


hello.py contents is simply:

import cherrypy
class HelloWorld:
    def index(self):
        return "Hello world!"
    index.exposed = True
if __name__ == '__main__':

Running python hello.py will start the web server and I can see the greeting in my browser at URL http://localhost:8080.

The tests directory has two files. __init__.py is empty. The test_hello.py follows closely the tutorial by Titus, but modified to work with CherryPy 3. The CherryPy 3 Upgrade instructions and CherryPy mod_wsgi instructions showed the way.

from StringIO import StringIO
import twill
import cherrypy
from hello import HelloWorld
class TestHelloWorld:
    def setUp(self):
        # configure cherrypy to be quiet ;)
        cherrypy.config.update({ "environment": "embedded" })
        # get WSGI app.
        wsgiApp = cherrypy.tree.mount(HelloWorld())
        # initialize
        # install the app at localhost:8080 for wsgi_intercept
        twill.add_wsgi_intercept('localhost', 8080, lambda : wsgiApp)
        # while we're at it, snarf twill's output.
        self.outp = StringIO()
    def tearDown(self):
        # remove intercept.
        twill.remove_wsgi_intercept('localhost', 8080)
        # shut down the cherrypy server.
    def test_hello(self):
        script = "find 'Hello world!'"
        twill.execute_string(script, initial_url='http://localhost:8080/')

Now you’d expect that this would work by simply running nosetests command. Mysteriously I got import error on twill (and after I removed the line, also import error on cherrypy). I looked at sys.path which showed that I was somehow picking up the older nosetests I had installed into system Python. which nosetests claimed it was finding the virtualenv nosetests. Still, I had to actually give the explicit path to my virtualenv nosetests before the tests would run without import errors.

All in all testing CherryPy applications turned into a longer adventure than I anticipated. I run into a number of unexpected difficulties, but I finally got it working and learned about twill as a bonus. Thanks for the tip, JJ!

Similar Posts:

    None Found


  1. Rene Dudfield:


    this is neat, thanks for sharing.

    One other technique with cherrypy apps is to test them like normal python objects.

    For example:

    def test_hello(self):
    self.assertTrue(“Hello world!” in HelloWorld().index())

    Functional tests are really nice to see it is working on a real webserver too 🙂


  2. Christian Wyglendowski:

    Nice post. Here is a bit of code that I put together at one point that uses Twill to test a CherryPy 3 app.


    It doesn’t use WSGI intercept – it launches the full CherryPy app server and tests against that.

  3. Heikki Toivonen:

    Thanks Rene, that was so simple it is embarrassing I did not realize that 🙂

    Christian, that looks interesting as well, thanks for sharing!

  4. Wyatt:

    I’ve found that when installing scripts into a virtualenv, I’ve often had to deactivate and then re-activate that virtualenv to get things to work properly.