This post contains examples of how unittest test fixture functions and methods are written, and in what order they run. It may seem like a long post, but it’s mostly code examples and example output.

I want this to be a useful reference for both the syntax and flow of unittest fixtures.
If I missed something, please comment below, and I’ll update the post.

Intro: Software Test Fixtures

The term test fixtures really means two things.
Test fixtures are the resources and initial conditions that a test needs to operate correctly and independently from other tests.
The phrase has also grown to mean the functions and methods that are used to do that resource and environment handling.

For the rest of this post, I’m really referring to the functions and methods when I say fixtures.

Test fixtures are methods and functions that run before and after a test.

The intent is to provide developers hooks to set up preconditions needed for the test, and cleanup after the test.

In many cases, this will be allocating, opening, or connecting to some resource in the setUp, and deallocating, closing, or disconnecting in the tearDown.

However, that’s just the intent. You can use these really however you want to use them.

One great use for fixtures is to set up structures or variables the same way for all tests.
This is to make sure that tests can run individually as well as a set and in any order.

Common Case Example

The most common fixture methods are setUp and tearDown.
The deserve to be the most common, because they are the ones that allow test independence.
The setUp() method runs before every test.
The tearDown() method runs after every test.

Here’s some code.

import unittest
import inspect

class TestLists(unittest.TestCase):

    def setUp(self):
        self.logPoint()
        self.myList = [1, 2, 3, 4]

    def test_len(self):
        self.logPoint()
        self.assertEqual( len(self.myList), 4 )
        self.myList.append(-1) 
        self.assertEqual( len(self.myList), 5 )

    def test_min(self):
        self.logPoint()
        self.assertEqual( min(self.myList) , 1 )

    def tearDown(self):
        self.logPoint() 

    def logPoint(self):
        currentTest = self.id().split('.')[-1]
        callingFunction = inspect.stack()[1][3]
        print 'in %s - %s()' % (currentTest, callingFunction)

And here’s the output.

> python -m unittest -q test_lists
in test_len - setUp()
in test_len - test_len()
in test_len - tearDown()
in test_min - setUp()
in test_min - test_min()
in test_min - tearDown()
----------------------------------------------------------------------
Ran 2 tests in 0.032s

OK

Note that the tests are wrapped with setUp() and tearDown() just as promised.

Tracing flow with logPoint()

In the code above, I’ve written a utility method logPoint() to demonstrate the control flow through the test.
I’m sure there’s a cleaner way to do this, but I couldn’t come up with a cleaner method.
I’m not going to describe the inspect module.
However, it is good to note I’m using the id() method that is part of unittest.TestCase to get the name of the current test. This is valid during the test method, as well as setUp, tearDown, and any methods called from the test method.

Full Test Fixture Example

Although setUp() and tearDown() are the methods that allow us to make sure each test can run independently and in any order, we have other methods available as well.

I think this is a complete list.

  • setUp() / tearDown()` – before and after test methods
  • setUpClass() / tearDownClass() – before and after a class of tests
  • setUpModule() / tearDownModule() – before and after a module of tests
  • Cleanup functions – extra tearDown methods that can be added at runtime to any test method during setUp, or during the test method itself.

Here’s some code with everything but cleanup functions.

import unittest
import inspect

def logPoint(context):
    'utility function used for module functions and class methods'
    callingFunction = inspect.stack()[1][3]
    print 'in %s - %s()' % (context, callingFunction)

def setUpModule():
    'called once, before anything else in this module'
    logPoint('module %s' % __name__)

def tearDownModule():
    'called once, after everything else in this module'
    logPoint('module %s' % __name__)

class TestFixtures(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        'called once, before any tests'
        logPoint('class %s' % cls.__name__)

    @classmethod
    def tearDownClass(cls):
        'called once, after all tests, if setUpClass successful'
        logPoint('class %s' % cls.__name__)

    def setUp(self):
        'called multiple times, before every test method'
        self.logPoint()

    def tearDown(self):
        'called multiple times, after every test method'
        self.logPoint()

    def test_1(self):
        'a test'
        self.logPoint()

    def test_2(self):
        'another test'
        self.logPoint()

    def logPoint(self):
        'utility method to trace control flow'
        callingFunction = inspect.stack()[1][3]
        currentTest = self.id().split('.')[-1]
        print 'in %s - %s()' % (currentTest, callingFunction)

Full Test Fixture Flow

> python -m unittest -q unittest_fixtures.TestFixtures
in module unittest_fixtures - setUpModule()
in class TestFixtures - setUpClass()
in test_1 - setUp()
in test_1 - test_1()
in test_1 - tearDown()
in test_2 - setUp()
in test_2 - test_2()
in test_2 - tearDown()
in class TestFixtures - tearDownClass()
in module unittest_fixtures - tearDownModule()
----------------------------------------------------------------------
Ran 2 tests in 0.026s

OK

Adding Cleanup Calls

Extra cleanup methods can be added from either a test or a setUp method.
Cleanup functions are called AFTER tearDown() but BEFORE tearDownClass()

class TestAddCleanup(TestFixtures):

    def setUp(self):
        TestFixtures.setUp(self)
        # --- add a cleanup method fixture for all tests
        def cleanup_a():
            self.logPoint()
        self.addCleanup(cleanup_a)

    def test_1(self):
        TestFixtures.test_1(self)
        # --- add a cleanup method fixture for just this test
        def cleanup_b():
            self.logPoint()
        self.addCleanup(cleanup_b)

    def test_2(self):
        TestFixtures.test_1(self)

Output

> python -m unittest -q unittest_fixtures.TestAddCleanup
in module unittest_fixtures - setUpModule()
in class TestAddCleanup - setUpClass()
in test_1 - setUp()
in test_1 - test_1()
in test_1 - tearDown()
in test_1 - cleanup_b()
in test_1 - cleanup_a()
in test_2 - setUp()
in test_2 - test_1()
in test_2 - tearDown()
in test_2 - cleanup_a()
in class TestAddCleanup - tearDownClass()
in module unittest_fixtures - tearDownModule()
----------------------------------------------------------------------
Ran 2 tests in 0.030s

OK

Skipping tests within setUp()

In the setUp method, you can decide to skip a test.
If skipped, the test will not be run.
ALSO, the tearDown method will not be run.

class TestSkip(TestFixtures):
    def setUp(self):
        TestFixtures.setUp(self)
        currentTest = self.id().split('.')[-1]
        if currentTest == 'test_2':
            self.skipTest('reason for skipping')
            # the 'reason' will displayed if '-v/--verbose' flag used

Output

> python -m unittest -q unittest_fixtures.TestSkip
in module unittest_fixtures - setUpModule()
in class TestSkip - setUpClass()
in test_1 - setUp()
in test_1 - test_1()
in test_1 - tearDown()
in test_2 - setUp()
in class TestSkip - tearDownClass()
in module unittest_fixtures - tearDownModule()
----------------------------------------------------------------------
Ran 2 tests in 0.018s

OK (skipped=1)

Exceptions in Fixtures

In all of the examples above, the test fixtures are really simple, and nothing can go wrong.
However, that’s not always the case, of course.
It’s important to understand what happens to your control flow if a test fixture fails in some way.

What happens if a test fixture function hits an assert or an exception?
That depends on the fixture method/function.

But…. that’s a topic for another post.
Specifically, What happens when unittest fixtures fail

Feedback, Please

Hopefully this has been informative, and I hope it will be a valuable reference for both the syntax and flow of unittest fixture functions and methods.

If this is helpful, I’d really like to know. Please leave a comment.
Feedback keeps me going.

Cheers.