In unittest fixture syntax and flow reference, I only presented fixture methods and functions that threw no exceptions.
However, in real production code, it is entirely possible for something to go wrong when setting up test fixtures.
This post is simply do demonstrate exactly what happens to the flow of your test code when an exception is thrown in a fixture function.
And, while I’m at it, I may as well demo the normal control flow when a test fails, asserts, or throws an exception.
To make the demo code small, I’m going to re-use the code from the previous post, derive my test classes from class TestFixtures
(also from that post), and only override one method at a time to show a failure.
If you want to follow along, you’ll want to put this at the top of your file:
from test_fixtures import TestFixtures, setUpModule, tearDownModule
class DemoException(Exception):
'exception to demostrate fixture/test failures'
pass
I’m using DemoException
to represent a failure in a fixture. However, an assert will be treated the same way.
Let’s look at the following:
- general concept
- exception in setUp()
- exception in tearDown()
- exception in setUpClass()
- exception in tearDownClass()
- exception in setUpModule()
- exception in tearDownModule()
- failure in a test
- assert in a test
- exception in a test
- feedback
General Concept
The general idea is that if a setUp type of method/function fails, then the enclosed tests are NOT run, and the matching tearDown is NOT run.
If a tearDown type of method/function fails, then the only difference from the good case is that the error is noted, and the test fails.
exception in setUp()
The module and class level fixtures are called, just as they would in good cases.
We see setUp being called for both tests.
Since setUp is failing, neither of the tests are run.
And the tearDown method is not run for either test.
class TestExceptionInSetUp(TestFixtures):
def setUp(self):
TestFixtures.setUp(self)
raise DemoException
Output
>python -m unittest -q test_fixture_failure.TestExceptionInSetUp
in module test_fixtures - setUpModule()
in class TestExceptionInSetUp - setUpClass()
in test_1 - setUp()
in test_2 - setUp()
in class TestExceptionInSetUp - tearDownClass()
in module test_fixtures - tearDownModule()
======================================================================
ERROR: test_1 (test_fixture_failure.TestExceptionInSetUp)
a test
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_fixture_failure.py", line 22, in setUp
raise DemoException
DemoException
======================================================================
ERROR: test_2 (test_fixture_failure.TestExceptionInSetUp)
another test
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_fixture_failure.py", line 22, in setUp
raise DemoException
DemoException
----------------------------------------------------------------------
Ran 2 tests in 0.014s
FAILED (errors=2)
exception in tearDown()
The flow looks identical to a successful test case, but the tearDown exception causes both tests to fail.
class TestExceptionInTearDown(TestFixtures):
def tearDown(self):
TestFixtures.tearDown(self)
raise DemoException
Output
>python -m unittest -q test_fixture_failure.TestExceptionInTearDown
in module test_fixtures - setUpModule()
in class TestExceptionInTearDown - 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 TestExceptionInTearDown - tearDownClass()
in module test_fixtures - tearDownModule()
======================================================================
ERROR: test_1 (test_fixture_failure.TestExceptionInTearDown)
a test
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_fixture_failure.py", line 27, in tearDown
raise DemoException
DemoException
======================================================================
ERROR: test_2 (test_fixture_failure.TestExceptionInTearDown)
another test
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_fixture_failure.py", line 27, in tearDown
raise DemoException
DemoException
----------------------------------------------------------------------
Ran 2 tests in 0.020s
FAILED (errors=2)
exception in setUpClass()
Module fixtures are run normally, but nothing else.
class TestExceptionInSetUpClass(TestFixtures):
@classmethod
def setUpClass(cls):
TestFixtures.setUpClass()
raise DemoException
Output
>python -m unittest -q test_fixture_failure.TestExceptionInSetUpClass
in module test_fixtures - setUpModule()
in class TestFixtures - setUpClass()
in module test_fixtures - tearDownModule()
======================================================================
ERROR: setUpClass (test_fixture_failure.TestExceptionInSetUpClass)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_fixture_failure.py", line 11, in setUpClass
raise DemoException
DemoException
----------------------------------------------------------------------
Ran 0 tests in 0.010s
FAILED (errors=1)
exception in tearDownClass()
Full test flow as in normal good tests, but the error is noted, and the test fails.
class TestExceptionInTearDownClass(TestFixtures):
@classmethod
def tearDownClass(cls):
TestFixtures.tearDownClass()
raise DemoException
Output
>python -m unittest -q test_fixture_failure.TestExceptionInTearDownClass
in module test_fixtures - setUpModule()
in class TestExceptionInTearDownClass - 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 test_fixtures - tearDownModule()
======================================================================
ERROR: tearDownClass (test_fixture_failure.TestExceptionInTearDownClass)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_fixture_failure.py", line 17, in tearDownClass
raise DemoException
DemoException
----------------------------------------------------------------------
Ran 2 tests in 0.020s
FAILED (errors=1)
exception in setUpModule()
To demostrate failure in module functions, I found it easiest just to copy the original test_fixtures.py file, and modify the setUpModule (or tearDownModule).
Not surprisingly, once setUpModule()
hits the exception, nothing else is run.
The tearDownModule()
is also not run, and the test records one error, and fails the test.
def setUpModule():
'called once, before anything else in this module'
logPoint('module %s' % __name__)
raise DemoException
Output
> python -m unittest -q test_setUpModule_fail.TestFixtures
in module test_setUpModule_fail - setUpModule()
======================================================================
ERROR: setUpModule (test_setUpModule_fail)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_setUpModule_fail.py", line 22, in setUpModule
raise DemoException
DemoException
----------------------------------------------------------------------
Ran 0 tests in 0.006s
FAILED (errors=1)
exception in tearDownModule()
Since tearDownModule()
is the last thing to be called when just running one module of tests, we see that all of the flow looks just like the good case. However, unittest does recognize the error, and fails the overall result.
def tearDownModule():
'called once, after everything else in this module'
logPoint('module %s' % __name__)
raise DemoException
Output
> python -m unittest -q test_tearDownModule_fail.TestFixtures
in module test_tearDownModule_fail - 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 test_tearDownModule_fail - tearDownModule()
======================================================================
ERROR: tearDownModule (test_tearDownModule_fail)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_tearDownModule_fail.py", line 26, in tearDownModule
raise DemoException
DemoException
----------------------------------------------------------------------
Ran 2 tests in 0.019s
FAILED (errors=1)
failure in a test
For test failures, asserts, and exceptions, I just wanted to demonstrate that all of the test fixtures are run, regardless of the test method outcome.
class TestFailInTest(TestFixtures):
def test_1(self):
TestFixtures.test_1(self)
self.fail()
Output
> python -m unittest -q test_fixture_failure.TestFailInTest
in module test_fixtures - setUpModule()
in class TestFailInTest - 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 TestFailInTest - tearDownClass()
in module test_fixtures - tearDownModule()
======================================================================
FAIL: test_1 (test_fixture_failure.TestFailInTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_fixture_failure.py", line 37, in test_1
self.fail()
AssertionError: None
----------------------------------------------------------------------
Ran 2 tests in 0.019s
FAILED (failures=1)
assert in a test
class TestAssertInTest(TestFixtures):
def test_1(self):
TestFixtures.test_1(self)
assert False
Output
> python -m unittest -q test_fixture_failure.TestAssertInTest
in module test_fixtures - setUpModule()
in class TestAssertInTest - 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 TestAssertInTest - tearDownClass()
in module test_fixtures - tearDownModule()
======================================================================
FAIL: test_1 (test_fixture_failure.TestAssertInTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_fixture_failure.py", line 42, in test_1
assert False
AssertionError
----------------------------------------------------------------------
Ran 2 tests in 0.020s
FAILED (failures=1)
exception in a test
class TestExceptionInTest(TestFixtures):
def test_1(self):
TestFixtures.test_1(self)
raise DemoException
Output
>python -m unittest -q test_fixture_failure.TestExceptionInTest
in module test_fixtures - setUpModule()
in class TestExceptionInTest - 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 TestExceptionInTest - tearDownClass()
in module test_fixtures - tearDownModule()
======================================================================
ERROR: test_1 (test_fixture_failure.TestExceptionInTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_fixture_failure.py", line 32, in test_1
raise DemoException
DemoException
----------------------------------------------------------------------
Ran 2 tests in 0.020s
FAILED (errors=1)
Feedback
As always, let me know if any of this info is incorrect or misleading.
Cheers.