Pot: nose

Posted by Patrice Neff Mon, 06 Apr 2009

nose is my Python testing tool of choice. You can use it to very easily create test suites.

While it does support the unittest module which is included with Python, it also allows for a much simple style using just methods and asserts.

Put the following code into a file called test_basic.py:

def test_addition():
    print 2 + 2
    assert 2 + 2 == 4
def test_addition_wrong():
    print 2 + 3
    assert 2 + 3 == 6

Then just run nosetests in the directory where you stored this file. You’ll
get an output indicating, that there is a test failure.

nose is based completely on naming conventions. Make sure your test files and methods all start with test for them to get executed. For assertions, just use assert.

When a test goes wrong you usually need some additional output to know what happened. nose helps you with this by handling print statements nicely. In the example above, as test_addition_wrong fails, you’ll see the output of the print statement print 2 + 3. But the print output of test_addition is suppressed because that test does not fail.

One of my favourite features of nose is Test generators. Often you have a large list of inputs and corresponding expected outputs for a function. Test generators allow you to easily test all of them without having to repeat the test code many times.

An example from a Nektoon test suite:

def test_browsers():
    tests = [('Mozilla/4.0 (compatible; MSIE 8.0)', 'msie', '8'),
        ('Mozilla/4.0 (compatible; MSIE 7.0b)', 'msie', '7')]
    for ua, model, version in tests:
        yield check_browser, ua, model, version
def check_browser(ua, model, version):
    res = parse_ua(ua)
    print res
    assert res['model'] == model
    assert res['version'] == version

The tests list is of course much bigger in our test suite and that’s the beauty of it. Adding a new test is very easy, but nose still provides very meaningful error output in the case of a test failure.

Read the official nose documentation if I was able to wet your appetite.

This post is part of the Python on the toilet series.

Continuous testing with Python

Posted by Patrice Neff Sat, 07 Feb 2009

Back when I did some Ruby on Rails development I was a big fan of autotest. With it I could stay in my editor while the project test suite got executed with every change.

Setup

Now that I’m working in Python I was looking for something similar and I was successful. You’ll need the following:

Then you can execute tdaemon like this in your project directory:

Usage

tdaemon.py --custom-args='--with-growl'

This will continually execute the test suite and notify you with growl about the status as you can see in this screencast:

Demo

Details

To get this working as shown in the screencast I actually had to make some changes.

First nosegrowl didn’t install well using easy_install as the images were missing. So I went ahead and did it manually:

$ hg clone http://hg.assembla.com/nosegrowl
$ cd nosegrowl/nose-growl/
$ sed -i.bak 's/growl.start/# growl.start/' nosegrowl/growler.py
$ python setup.py install

The 'sed’ command is optional. But I don’t want to be notified when the test suite starts, only when it ends. So I uncomment the growl.start line.

Additionally to make tdaemon less noisy when working with vim I added the swap files to the exclude list. Open the tdaemon.py file and edit the IGNORE_EXTENSIONS line to look like this:

IGNORE_EXTENSIONS = ('pyc', 'pyo', 'swp')