Latest Version: 0.9.6.2

Warning

This documentation does not refer to the most recent version of Pylons. Current Documentation

Unit Testing with paste.fixture

Pylons provides powerful unit testing capabilities for your web application utilizing paste.fixture to emulate requests to your web application. You can then ensure that the response was handled appropriately and that the controller set things up properly.

To run the test suite for your web application, Pylons utilizes the nose test runner/discovery package. Running nosetests in your project directory will run all the tests you create in the tests directory. If you don't have nose installed on your system, it can be installed via setuptools with:

easy_install -U nose

Note: paste.fixture is currently incompatible with Windows, we are working on remedying this.

Testing Pylons Objects

Pylons will provide several additional attributes for the paste.fixture response object that let you access various objects that were created during the web request:

session
Session object
request
Request object
m
Myghty object
comp_calls

List of component calls, including any scomp, comp, and subexec thats executed during the request. Each item of the list is a dict with the keys:

comp_type
The type of component call, i.e. scomp, comp, or subexec
template
Template name that was called, i.e. /some/template.myt
params
Dict of keyword args that the component was called with

To use them, merely access the attributes of the response after you've used a get/post command:

response = app.get('/some/url')
assert response.session['var'] == 4

Example: Testing a Controller

First let's create a new project and controller for this example:

paster create --template=pylons TestExample
cd TestExample
paster controller comments

You'll see that it creates two files when you create a controller. The stub controller, and a test for it under testexample/tests/functional/.

Modify the testexample/controllers/comments.py file so it looks like this:

from testexample.lib.base import *

class CommentsController(BaseController):
    def index(self):
        m.write('Basic output')

    def sess(self):
        session['name'] = 'Joe Smith'
        session.save()
        m.write('Saved a session')

Then write a basic set of tests to ensure that the controller actions are functioning properly, modify testexample/tests/functions/test_comments.py to match the following:

from testexample.tests import *

class TestCommentsController(TestController):
    def test_index(self):
        response = self.app.get(url_for(controller='/comments'))
        assert 'Basic output' in response

    def test_sess(self):
        response = self.app.get(url_for(controller='/comments', action='sess'))
        assert response.session['name'] == 'Joe Smith'
        assert 'Saved a session' in response

Run nosetests in your main project directory and you should see them all pass:

..
----------------------------------------------------------------------
Ran 2 tests in 2.999s

OK

Unfortunately, nosetests (as of 0.8.6 at least) cannot provide detailed information about the results of an assertion should it fail when you use this format for testing. For example, add the following test to the test_sess function:

assert response.session.has_key('address') == True

When you run nosetests you will get the following, not-very-helpful response:

.F
======================================================================
FAIL: test_sess (testexample.tests.functional.test_comments.TestCommentsController)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "~/TestExample/testexample/tests/functional/test_comments.py", line 12, in test_sess
    assert response.session.has_key('address') == True
AssertionError:


----------------------------------------------------------------------
Ran 2 tests in 1.417s

FAILED (failures=1)

Since our TestController we inherited from is a standard Python unit testing controller we can use the assertEqual statement which will provide more information. The new test line looks like this:

self.assertEqual(response.session.has_key('address'), True)

Which provides the more useful failure message:

.F
======================================================================
FAIL: test_sess (testexample.tests.functional.test_comments.TestCommentsController)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "~/TestExample/testexample/tests/functional/test_comments.py", line 12, in test_sess
    self.assertEqual(response.session.has_key('address'), True)
AssertionError: False != True

For more details on running tests using get/post, and testing the response, headers, etc., see the Paste document on web application testing:

Testing Application with Paste, the Tests

Top