Nose Unit Testing Quick Start

This is just a quick "get up and running fast" walk through on using the Nose Unit Testing framework. The reference documentation for Nose is great, but their site seems a little light on the quick start side. I assume you have python installed. If you're unsure how to install python, see your OS documentation.

Install Nose

Install Nose using your OS's package manager or with easy_install. For example:

% easy_install nose

Create Some Code for Testing

As an example, I've created the class below I'll use in the unit test examples.

class A(object):
    def __init__(self):
        self.value = "Some Value"def return_true(self):
        return True
    def raise_exc(self, val):
        raise KeyError(val)

Create Unit Test Classes

There are many approaches to writing Nose unit tests. I normally write a test class for each class or module I wish to test. Nose will load and run any class whose name is preceded by Test such as TestClassA or TestA. When it discovers a class, it uses its default testMatch regex to find any methods that match. Again, we'll use the test_method() convention for our tests. For more information see the  Writing Tests reference.

A few notes on the testing example.

  1. Nose supports fixtures, though we won't use them here. I have included the fixture methods in the below example, but only provide a comment explaining their use in the source.
  2. The nose.tools packages comes with many helper methods that make testing syntactically clearer for common test cases. In this example, we use assert_equal, assert_not_equal, the raises decorator, and assert_raises. For a full list see the nose.tools documentation.
  3. For organizational purposes, I create a subdirectory in my project called "tests". This is not required.
from a import A
from nose.tools import assert_equal
from nose.tools import assert_not_equal
from nose.tools import assert_raises
from nose.tools import raises


class TestA(object):
    @classmethod
    def setup_class(klass):
        """This method is run once for each class before any tests are run"""

    @classmethod
    def teardown_class(klass):
        """This method is run once for each class _after_ all tests are run"""

    def setUp(self):
        """This method is run once before _each_ test method is executed"""

    def teardown(self):
        """This method is run once after _each_ test method is executed"""

    def test_init(self):
        a = A()
        assert_equal(a.value, "Some Value")
        assert_not_equal(a.value, "Incorrect Value")

    def test_return_true(self):
        a = A()
        assert_equal(a.return_true(), True)
        assert_not_equal(a.return_true(), False)

    def test_raise_exc(self):
        a = A()
        assert_raises(KeyError, a.raise_exc, "A value")

    @raises(KeyError)
    def test_raise_exc_with_decorator(self):
        a = A()
        a.raise_exc("A message")

Run Tests

All that's left is to run our tests. Nose comes with a command line utility called 'nosetests'. The simplest usage is to call nosetests from within your project directory and pass the 'tests' directory as an argument. For example,

% nosetests tests

For our examples, this outputs the following test summary:

 % nosetests tests
....
----------------------------------------------------------------------
Ran 4 tests in 0.003s  OK

Adding Code Coverage

One useful metric for the completeness of your unit tests is the concept of code coverage. Nose comes out of the box with support for the coverage module. First, install coverage using your package manager or by:

% easy_install coverage

To generate a coverage report using the nosetests utility, simply add the --with-coverage. By default, coverage generates data for all modules found in the current directory.

% nosetests --with-coverage

If you've included a few 3rd party modules, then you could be looking at a lot of information you don't care much about. If this is the case, you can also specify the specific modules you wish to run reports on. In our example, you would do so by running

% nosetests --with-coverage --cover-package a

The --cover-package switch can be used multiple times. If you had a b.py, you could

% nosetests --with-coverage --cover-package a --cover-package b

If we run coverage on our example tests, we get:

% nosetests --with-coverage
....
Name    Stmts   Miss  Cover   Missing
-------------------------------------
a           8      0   100%
----------------------------------------------------------------------
Ran 4 tests in 0.006sOK

Share on: TwitterFacebookGoogle+Email

Comments !