This post has several examples, and covers fixtures, test discovery, asserts, running options, and running unittests and doctests.

Nose’s tagline is “nose extends unittest to make testing easier”.
It’s is a fairly well known python unit test framework, and can run doctests, unittests, and “no boilerplate” tests.

It is a good candidate for a go-to test framework.

I think a smart developer should get familiar doctest, unittest, pytest, and nose. Then decide if one of those makes the most sense for them, or if they want to keep looking for features only found in other frameworks.
That’s of course the reason why I’m writing this series. So I guess that last bit goes without saying.

Contents

No boilerplate, some api

A basic test file for nose is pretty simple, without any boilerplate code, without required classes to drive from, without unnecessary imports, and without any extra api.

Note:
The module unnecessary_math is non-standard and can be found here: implementation of unnecessary_math.py

from unnecessary_math import multiply

def test_numbers_3_4():
    assert multiply(3,4) == 12 

This is identical to the simple test shown in my pytest intro.
There are differences between how you have to write your tests for the two frameworks once you get into extra features of the frameworks, like fixtures, plugins, assert mechanisms, etc.
I’m going to leave a full comparison of pytest and nose to a future post.

Why do I say ‘some api’? Well, when you get into fixtures (like setup/teardown, etc), there is some nose api that is needed in the tests. I’ll get into that in the fixture section.

Nose example

For completeness in following the styles of previous framework introductions, here is the full basic test.
This only differs from above that I’ve added another test function.

from unnecessary_math import multiply

def test_numbers_3_4():
    assert multiply(3,4) == 12 

def test_strings_a_3():
    assert multiply('a',3) == 'aaa' 

Running nose

To run nose, use the nosetests command that comes with nose.

nosetests test_um_nose.py

And with verbose:

nosetests -v test_um_nose.py

Here’s an example run both with and without verbose:

> nosetests test_um_nose.py
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK
> nosetests -v test_um_nose.py
simple_example.test_um_nose.test_numbers_3_4 ... ok
simple_example.test_um_nose.test_strings_a_3 ... ok

----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK

Nose fixtures

Nose extends the unittest fixture model of setup/teardown.

We can add specific code to run:

  • at the beginning and end of a module of test code (setup_module/teardown_module)
    To get this to work, you just have to use the right naming rules.

  • at the beginning and end of a class of test methods (setup_class/teardown_class)
    To get this to work, you have to use the right naming rules, and include the ‘@classmethod’ decorator.

  • before and after a test function call (setup_function/teardown_function)
    You can use any name. You have to apply them with the ‘@with_setup’ decorator imported from nose.
    You can also use direct assignment, which I’ll show in the example.

  • before and after a test method call (setup/teardown)
    To get this to work, you have to use the right name.

The easiest fixtures to add are:

  • setup_module() function: runs before anything else in the file
  • teardown_module() function: runs after everything else in the file

And if you use a class to define some tests:

  • setup() method: runs before every test method
  • teardown() method: runs after every test method

You can also set non-class based test functions to have setup/teardown
functions, but you have to import the ‘with_setup’ decorator from nose, like so:

from nose import with_setup # optional

def my_setup_function():
    pass

def my_teardown_function():
    pass

@with_setup(my_setup_function, my_teardown_function)
def test_numbers_3_4():
    assert multiply(3,4) == 12 

If you don’t like to use decorators, you can also assign the setup and teardown attributes like this:

test_numbers_3_4.setup = my_setup_function
test_numbers_3_4.teardown = my_teardown_function

However, I think that’s a bit awkward.

With classes, you can set a setup/teardown for the class, but you do it differently.
You need to make sure the methods are class methods using the ‘classmethod’ decorator, and name them correctly, like so:

class TestUM:

    @classmethod
    def setup_class(cls):
        print ("setup_class() before any methods in this class")

    @classmethod
    def teardown_class(cls):
        print ("teardown_class() after any methods in this class")

It works, it’s just that you have to keep the syntax straight for all the different rules for different fixtures.

Here they are all together.

from nose import with_setup # optional

from unnecessary_math import multiply

def setup_module(module):
    print ("") # this is to get a newline after the dots
    print ("setup_module before anything in this file")

def teardown_module(module):
    print ("teardown_module after everything in this file")

def my_setup_function():
    print ("my_setup_function")

def my_teardown_function():
    print ("my_teardown_function")

@with_setup(my_setup_function, my_teardown_function)
def test_numbers_3_4():
    print 'test_numbers_3_4  <============================ actual test code'
    assert multiply(3,4) == 12

@with_setup(my_setup_function, my_teardown_function)
def test_strings_a_3():
    print 'test_strings_a_3  <============================ actual test code'
    assert multiply('a',3) == 'aaa'


class TestUM:

    def setup(self):
        print ("TestUM:setup() before each test method")

    def teardown(self):
        print ("TestUM:teardown() after each test method")

    @classmethod
    def setup_class(cls):
        print ("setup_class() before any methods in this class")

    @classmethod
    def teardown_class(cls):
        print ("teardown_class() after any methods in this class")

    def test_numbers_5_6(self):
        print 'test_numbers_5_6()  <============================ actual test code'
        assert multiply(5,6) == 30

    def test_strings_b_2(self):
        print 'test_strings_b_2()  <============================ actual test code'
        assert multiply('b',2) == 'bb'

To see it in action, I’ll use the -s option, which turns off output capture.
This will show the order of the different fixture calls.

> nosetests -s test_um_nose_fixtures.py
....
setup_module before anything in this file
setup_class() before any methods in this class
TestUM:setup() before each test method
test_numbers_5_6()  <============================ actual test code
TestUM:teardown() after each test method
TestUM:setup() before each test method
test_strings_b_2()  <============================ actual test code
TestUM:teardown() after each test method
teardown_class() after any methods in this class
my_setup_function
test_numbers_3_4  <============================ actual test code
my_teardown_function
my_setup_function
test_strings_a_3  <============================ actual test code
my_teardown_function
teardown_module after everything in this file

----------------------------------------------------------------------
Ran 4 tests in 0.001s

OK

Testing markdown.py

This is also identical to code that can be run from py.test.
It’s similar to unittest code, but without boilerplate, and with simple assert calls instead of assertEquals.
Again, I’m using the API adapter to cleanly call markdown functionality.

Here’s the code to use nose to test markdown.py:

from markdown_adapter import run_markdown

def test_non_marked_lines():
    print ('in test_non_marked_lines')
    assert run_markdown('this line has no special handling') \
            == 'this line has no special handling</p>'

def test_em():
    print ('in test_em')
    assert run_markdown('*this should be wrapped in em tags*') \
            == '<p><em>this should be wrapped in em tags</em></p>'

def test_strong():
    print ('in test_strong')
    assert run_markdown('**this should be wrapped in strong tags**') \
            == '<p><strong>this should be wrapped in strong tags</strong></p>'

And here’s the output:

> nosetests  test_markdown_nose.py
FFF
======================================================================
FAIL: test_markdown_nose.test_non_marked_lines
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\python27\lib\site-packages\nose-1.2.1-py2.7.egg\nose\case.py", line 197, in runTest
    self.test(*self.arg)
  File "E:\python_notes\repo\markdown.py-dev\test_markdown_nose.py", line 13, in test_non_marked_lines
    == 'this line has no special handling</p>'
AssertionError:
-------------------- >> begin captured stdout << ---------------------
in test_non_marked_lines

--------------------- >> end captured stdout << ----------------------

======================================================================
FAIL: test_markdown_nose.test_em
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\python27\lib\site-packages\nose-1.2.1-py2.7.egg\nose\case.py", line 197, in runTest
    self.test(*self.arg)
  File "E:\python_notes\repo\markdown.py-dev\test_markdown_nose.py", line 18, in test_em
    == '<p><em>this should be wrapped in em tags</em></p>'
AssertionError:
-------------------- >> begin captured stdout << ---------------------
in test_em

--------------------- >> end captured stdout << ----------------------

======================================================================
FAIL: test_markdown_nose.test_strong
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\python27\lib\site-packages\nose-1.2.1-py2.7.egg\nose\case.py", line 197, in runTest
    self.test(*self.arg)
  File "E:\python_notes\repo\markdown.py-dev\test_markdown_nose.py", line 23, in test_strong
    == '<p><strong>this should be wrapped in strong tags</strong></p>'
AssertionError:
-------------------- >> begin captured stdout << ---------------------
in test_strong

--------------------- >> end captured stdout << ----------------------

----------------------------------------------------------------------
Ran 3 tests in 0.137s

FAILED (failures=3)

All of the tests are failing.
Although the line numbers of the failures, along with the test function names, are printed, it’s not real obvious from the report what’s wrong.

Nose assert_equals

If we are using lots of assert something == somethingElse type tests, and we are committed to using nose for testing, we can use nose tools to make the report a bit obvious about what the failure is.

I’m going to rewrite the tests from above using nose.tools.assert_equals:

from nose.tools import assert_equals
from markdown_adapter import run_markdown

def test_non_marked_lines():
    print ('in test_non_marked_lines')
    assert_equals(run_markdown('this line has no special handling'),
        'this line has no special handling</p>')

def test_em():
    print ('in test_em')
    assert_equals( run_markdown('*this should be wrapped in em tags*'),
        '<p><em>this should be wrapped in em tags</em></p>')

def test_strong():
    print ('in test_strong')
    assert_equals( run_markdown('**this should be wrapped in strong tags**'),
        '<p><strong>this should be wrapped in strong tags</strong></p>')

Nose’s assert_equals works a lot like unittest’s assertEquals.

Now lets look at the output:

> nosetests test_markdown_nose_assert_equals.py
FFF
======================================================================
FAIL: test_markdown_nose_assert_equals.test_non_marked_lines
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\python27\lib\site-packages\nose-1.2.1-py2.7.egg\nose\case.py", line 197, in runTest
    self.test(*self.arg)
  File "E:\python_notes\repo\markdown.py-dev\test_markdown_nose_assert_equals.py", line 14, in test_non_marked_lines
    'this line has no special handling</p>')
AssertionError: 'this line has no special handling' != '<p>this line has no special handling</p>'
-------------------- >> begin captured stdout << ---------------------
in test_non_marked_lines

--------------------- >> end captured stdout << ----------------------

======================================================================
FAIL: test_markdown_nose_assert_equals.test_em
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\python27\lib\site-packages\nose-1.2.1-py2.7.egg\nose\case.py", line 197, in runTest
    self.test(*self.arg)
  File "E:\python_notes\repo\markdown.py-dev\test_markdown_nose_assert_equals.py", line 19, in test_em
    '<p><em>this should be wrapped in em tags</em></p>')
AssertionError: '*this should be wrapped in em tags*' != '<p><em>this should be wrapped in em tags</em></p>'
-------------------- >> begin captured stdout << ---------------------
in test_em

--------------------- >> end captured stdout << ----------------------

======================================================================
FAIL: test_markdown_nose_assert_equals.test_strong
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\python27\lib\site-packages\nose-1.2.1-py2.7.egg\nose\case.py", line 197, in runTest
    self.test(*self.arg)
  File "E:\python_notes\repo\markdown.py-dev\test_markdown_nose_assert_equals.py", line 24, in test_strong
    '<p><strong>this should be wrapped in strong tags</strong></p>')
AssertionError: '**this should be wrapped in strong tags**' != '<p><strong>this should be wrapped in strong tags</strong></p>'
-------------------- >> begin captured stdout << ---------------------
in test_strong

--------------------- >> end captured stdout << ----------------------

----------------------------------------------------------------------
Ran 3 tests in 0.139s

FAILED (failures=3)

Now the output makes it more obvious what’s wrong.

Test discovery

I use the same naming conventions for nose as I do for py.test.

  • Name my test modules/files starting with ‘test_’.
  • Name my test functions starting with ‘test_’.
  • Name my test classes starting with ‘Test’.
  • Name my test methods starting with ‘test_’.
  • Make sure all packages with test code have an ‘init.py’ file.

These rules work just fine for me.

This isn’t the complete list of rules. If you want to do something different, look at the nose documentation for finding tests

Running unittests from nose

Nose finds and runs unittests with no problem, and with no extra steps.
Here I’ll run the tests from the unittest intro:

> nosetests test_um_unittest.py
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK
> nosetests -v test_um_unittest.py
test_numbers_3_4 (simple_example.test_um_unittest.TestUM) ... ok
test_strings_a_3 (simple_example.test_um_unittest.TestUM) ... ok

----------------------------------------------------------------------
Ran 2 tests in 0.001s

OK

Running doctests from nose

Nose can run doctests, supposedly.
However, I couldn’t get it to work on doctests in a separate file method, using test_unnecessary_math.txt.

I tried several of the options, with no luck.
If you know what I’m doing wrong, please let me know.

More nose info (links)

Examples on github

All of the examples here are available in the markdown.py project on github.