Python’s
Module: unittest
Purpose: Automated testing framework
Python Version: 2.1
Basic Test Structure:
Tests, as defined by the
In this case, the
Running Tests:
The simplest way to run unittest tests is to include:
at the bottom of each test file, then simply run the script directly from the command line:
This abbreviated output includes the amount of time the tests took, along with a status indicator for each test (the “.” on the first line of output means that a test passed). For more detailed test results, include the -v option:
Test Outcomes:
Tests have 3 possible outcomes:
There is no explicit way to cause a test to “pass”, so a test’s status depends on the presence (or absence) of an exception.
When a test fails or generates an error, the traceback is included in the output.
In the example above,
Asserting Truth:
Most tests assert the truth of some condition. There are a few different ways to write truth-checking tests, depending on the perspective of the test author and the desired outcome of the code being tested. If the code produces a value which can be evaluated as true, the methods
Testing Equality:
As a special case,
These special tests are handy, since the values being compared appear in the failure message when a test fails.
And when these tests are run:
Almost Equal?
In addition to strict equality, it is possible to test for near equality of floating point numbers using
The arguments are the 2 values to be compared, and the number of decimal places to use for the test.
Testing for Exceptions:
As previously mentioned, if a test raises an exception it is treated as an error in the test. This is very useful for uncovering mistakes while you are modifying code which has existing test coverage. There are circumstances, however, in which you want the test to verify that some code does produce an exception. For example, if an invalid value is given to an attribute of an object. In such cases,
The results for both are the same, but the second test using
Test Fixtures:
Fixtures are resources needed by a test. For example, if you are writing several tests for the same class, those tests all need an instance of that class to use for testing. Other test fixtures include database connections and temporary files (many people would argue that using external resources makes such tests not “unit” tests, but they are still tests and still useful).
When this sample test is run, you can see the order of execution of the fixture and test methods:
Test Suites:
The standard library documentation describes how to organize test suites manually. I generally do not use test suites directly, because I prefer to build the suites automatically (these are automated tests, after all). Automating the construction of test suites is especially useful for large code bases, in which related tests are not all in the same place. Tools such as nose and Proctor make it easier to manage tests when they are spread over multiple files and directories.
References:
Python Module of the Week Home
Download Sample Code
unittest module, sometimes referred to as PyUnit, is based on the XUnit framework design by Kent Beck and Erich Gamma. The same pattern is repeated in many other languages, including C, perl, Java, and Smalltalk. The framework implemented by unittest supports fixtures, test suites, and a test runner to enable automated testing for your code.
Module: unittest
Purpose: Automated testing framework
Python Version: 2.1
Basic Test Structure:
Tests, as defined by the
unittest module, have two parts: code to manage test “fixtures”, and the test itself. Individual tests are created by subclassing unittest.TestCase and overriding or adding appropriate methods. For example,import unittest
class SimplisticTest(unittest.TestCase):
def test(self):
self.failUnless(True)
if __name__ == '__main__':
unittest.main()
In this case, the
SimplisticTest has a single test() method, which would fail if True is ever False. Running Tests:
The simplest way to run unittest tests is to include:
if __name__ == '__main__':
unittest.main()
at the bottom of each test file, then simply run the script directly from the command line:
$ python unittest_simple.py
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
This abbreviated output includes the amount of time the tests took, along with a status indicator for each test (the “.” on the first line of output means that a test passed). For more detailed test results, include the -v option:
$ python unittest_simple.py -v
test (__main__.SimplisticTest) ... ok
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK
Test Outcomes:
Tests have 3 possible outcomes:
- ok
- The test passes.
- FAIL
- The test does not pass, and raises an
AssertionErrorexception. - ERROR
- The test raises an exception other than
AssertionError.
There is no explicit way to cause a test to “pass”, so a test’s status depends on the presence (or absence) of an exception.
class OutcomesTest(unittest.TestCase):
def testPass(self):
return
def testFail(self):
self.failIf(True)
def testError(self):
raise RuntimeError('Test error!')
When a test fails or generates an error, the traceback is included in the output.
$ python unittest_outcomes.py
EF.
======================================================================
ERROR: testError (__main__.OutcomesTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "unittest_outcomes.py", line 43, in testError
raise RuntimeError('Test error!')
RuntimeError: Test error!
======================================================================
FAIL: testFail (__main__.OutcomesTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "unittest_outcomes.py", line 40, in testFail
self.failIf(True)
AssertionError
----------------------------------------------------------------------
Ran 3 tests in 0.002s
FAILED (failures=1, errors=1)
In the example above,
testFail() fails and the traceback shows the line with the failure code. It is up to the person reading the test output to look at the code to figure out the semantic meaning of the failed test, though. To make it easier to understand the nature of a test failure, the fail*() and assert*() methods all accept an argument msg, which can be used to produce a more detailed error message.class FailureMessageTest(unittest.TestCase):
def testFail(self):
self.failIf(True, 'failure message goes here')
$ python unittest_failwithmessage.py -vtestFail (__main__.FailureMessageTest) ... FAIL
======================================================================
FAIL: testFail (__main__.FailureMessageTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "unittest_failwithmessage.py", line 37, in testFail
self.failIf(True, 'failure message goes here')
AssertionError: failure message goes here
----------------------------------------------------------------------
Ran 1 test in 0.002s
FAILED (failures=1)
Asserting Truth:
Most tests assert the truth of some condition. There are a few different ways to write truth-checking tests, depending on the perspective of the test author and the desired outcome of the code being tested. If the code produces a value which can be evaluated as true, the methods
failUnless() and assertTrue() should be used. If the code produces a false value, the methods failIf() and assertFalse() make more sense. class TruthTest(unittest.TestCase):
def testFailUnless(self):
self.failUnless(True)
def testAssertTrue(self):
self.assertTrue(True)
def testFailIf(self):
self.failIf(False)
def testAssertFalse(self):
self.assertFalse(False)
Testing Equality:
As a special case,
unittest includes methods for testing the equality of two values. class EqualityTest(unittest.TestCase):
def testEqual(self):
self.failUnlessEqual(1, 3-2)
def testNotEqual(self):
self.failIfEqual(2, 3-2)
These special tests are handy, since the values being compared appear in the failure message when a test fails.
class InequalityTest(unittest.TestCase):
def testEqual(self):
self.failIfEqual(1, 3-2)
def testNotEqual(self):
self.failUnlessEqual(2, 3-2)
And when these tests are run:
$ python unittest_notequal.py -v
testEqual (__main__.EqualityTest) ... FAIL
testNotEqual (__main__.EqualityTest) ... FAIL
======================================================================
FAIL: testEqual (__main__.EqualityTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "unittest_notequal.py", line 37, in testEqual
self.failIfEqual(1, 3-2)
AssertionError: 1 == 1
======================================================================
FAIL: testNotEqual (__main__.EqualityTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "unittest_notequal.py", line 40, in testNotEqual
self.failUnlessEqual(2, 3-2)
AssertionError: 2 != 1
----------------------------------------------------------------------
Ran 2 tests in 0.002s
FAILED (failures=2)
Almost Equal?
In addition to strict equality, it is possible to test for near equality of floating point numbers using
failIfAlmostEqual() and failUnlessAlmostEqual().class AlmostEqualTest(unittest.TestCase):
def testNotAlmostEqual(self):
self.failIfAlmostEqual(1.1, 3.3-2.0, places=1)
def testAlmostEqual(self):
self.failUnlessAlmostEqual(1.1, 3.3-2.0, places=0)
The arguments are the 2 values to be compared, and the number of decimal places to use for the test.
$ python unittest_almostequal.py
..
----------------------------------------------------------------------
Ran 2 tests in 0.001s
OK
Testing for Exceptions:
As previously mentioned, if a test raises an exception it is treated as an error in the test. This is very useful for uncovering mistakes while you are modifying code which has existing test coverage. There are circumstances, however, in which you want the test to verify that some code does produce an exception. For example, if an invalid value is given to an attribute of an object. In such cases,
TestCase.failUnlessRaises() makes the code more clear than trapping the exception yourself. Compare these two tests:def raises_error(*args, **kwds):
print args, kwds
raise ValueError('Invalid value: ' + str(args) + str(kwds))
class ExceptionTest(unittest.TestCase):
def testTrapLocally(self):
try:
raises_error('a', b='c')
except ValueError:
pass
else:
self.fail('Did not see ValueError')
def testFailUnlessRaises(self):
self.failUnlessRaises(ValueError, raises_error, 'a', b='c')
The results for both are the same, but the second test using
failUnlessRaises() is more succinct.$ python unittest_exception.py -v
testFailUnlessRaises (__main__.ExceptionTest) ... ('a',) {'b': 'c'}
ok
testTrapLocally (__main__.ExceptionTest) ... ('a',) {'b': 'c'}
ok
----------------------------------------------------------------------
Ran 2 tests in 0.001s
OK
Test Fixtures:
Fixtures are resources needed by a test. For example, if you are writing several tests for the same class, those tests all need an instance of that class to use for testing. Other test fixtures include database connections and temporary files (many people would argue that using external resources makes such tests not “unit” tests, but they are still tests and still useful).
TestCase includes a special hook to configure and clean up any fixtures needed by your tests. To configure the fixtures, override setUp(). To clean up, override tearDown().class FixturesTest(unittest.TestCase):
def setUp(self):
print 'In setUp()'
self.fixture = range(1, 10)
def tearDown(self):
print 'In tearDown()'
del self.fixture
def test(self):
print 'in test()'
self.failUnlessEqual(self.fixture, range(1, 10))
When this sample test is run, you can see the order of execution of the fixture and test methods:
$ python unittest_fixtures.py
In setUp()
in test()
In tearDown()
.
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK
Test Suites:
The standard library documentation describes how to organize test suites manually. I generally do not use test suites directly, because I prefer to build the suites automatically (these are automated tests, after all). Automating the construction of test suites is especially useful for large code bases, in which related tests are not all in the same place. Tools such as nose and Proctor make it easier to manage tests when they are spread over multiple files and directories.
References:
Python Module of the Week Home
Download Sample Code
Technorati Tags:
python, PyMOTW

