Unit Testing with Python

Unit testing is considered an essential part of software development. Through unit testing, we can evaluate each code component, find out how well it performs, and determine how well it reacts to valid or invalid input. A regression suite of unit tests is also an excellent way of detecting unexpected changes in a code base caused by refactoring or writing new code.

In this article, I examine the mechanisms of unit testing in Python, starting with the unittest module and its key classes. I examine tests individually and in suites, and I discuss how to facilitate their construction and use. Readers should have a working knowledge of Python. The sample test code requires Python 2.5 or later.

The unittest Module

The unittest module started life as the third-party module PyUnit. PyUnit was a Python port of JUnit, the Java unit testing framework. Designed by Steve Purcell, PyUnit became an official Python module starting with version 2.5.

Python Unit Tests
Figure 1: Core classes in unittest.

As Figure 1 shows, there are five key classes in the unittest module. The TestCase class holds the test routines and provides hooks for preparing each routine and for cleaning up after. The TestSuite class serves as a collection container. It can hold multiple TestCase objects and multiple TestSuite objects.

The TestLoader class loads test cases and suites defined locally or from an external file. It emits a TestSuite object that holds those cases and suites. The TextTestRunner class provides a standard platform to run the tests. The TestResults class provides a standard container for the test results.

Out of these five classes, only TestCase must be subclassed. The other four classes can also be subclassed, but they are generally used as is.

 

Preparing a Test Case

Figure 2 shows the structure of the TestCase class. In it are three sets of methods that are used most often in designing the tests. In the first set are the pre- and post-test hooks. The setUp() method fires before each test routine, the tearDown() after the routine. Override these methods when you create a custom test case.

Python Unit Tests
Figure 2: The structure of a TestCase class.

The second pair of methods control test execution. Both methods take a message string as input, and both abort an ongoing test. But the skipTest() method cancels the current test, while the fail() method fails it explicitly.

The third set of methods help identify the test. The method id() returns a string containing the name of the TestCase object and of the test routine. And the method shortDescription() returns the docstr comment at the start of each test routine. If the routine has no such comment, shortDescription() returns a None.

Listing One shows the sample bare bones test case FooTest. FooTest has two test routines: testA() and testB(). Both routines get the required argument of self. Both have a docstr comment for a first line.

Listing One: Code to show the sequence of unit test execution.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/usr/bin/python
import unittest
class FooTest(unittest.TestCase):
    """Sample test case"""
    
    # preparing to test
    def setUp(self):
        """ Setting up for the test """
        print "FooTest:setUp_:begin"
        ## do something...
        print "FooTest:setUp_:end"
    
    # ending the test
    def tearDown(self):
        """Cleaning up after the test"""
        print "FooTest:tearDown_:begin"
        ## do something...
        print "FooTest:tearDown_:end"
    
    # test routine A
    def testA(self):
        """Test routine A"""
        print "FooTest:testA"
    
    # test routine B
    def testB(self):
        """Test routine B"""
        print "FooTest:testB"

Figure 3 shows how FooTest behaves when executed.

Python Unit Tests
Figure 3: FooTest behavior.

Note the same setUp() and tearDown() methods run before and after each test routine. So how do you let setUp() and tearDown() know which routine is being run?  You must first identify the routine by calling shortDescription() or id() (See Listing Two). Then use an if-else block to route to the appropriate code. In the sample snippet, FooTest calls shortDescription() to get the routine’s docstr comment, then runs the prep and clean-up code for that routine.

Listing Two: Using test descriptions.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import unittest
class FooTest(unittest.TestCase):
    """Sample test case"""
    
    # preparing to test
    def setUp(self):
        """ Setting up for the test """
        print "FooTest:setUp_:begin"
        
        testName = self.shortDescription()
        if (testName == "Test routine A"):
            print "setting up for test A"
            
        elif (testName == "Test routine B"):
            print "setting up for test B"
            
        else:
            print "UNKNOWN TEST ROUTINE"
            
        print "FooTest:setUp_:end"
    
    # ending the test
    def tearDown(self):
        """Cleaning up after the test"""
        print "FooTest:tearDown_:begin"
        
        testName = self.shortDescription()
        if (testName == "Test routine A"):
            print "cleaning up after test A"
            
        elif (testName == "Test routine B"):
            print "cleaning up after test B"
            
        else:
            print "UNKNOWN TEST ROUTINE"
            
        print "FooTest:tearDown_:end"
    
    # see Listing One...

Designing a Test Routine

Each test routine must have the prefix “test” in its name. Without that prefix, the routine will not run. To perform a test, the test routine should use an assert method. An assert method gets one or more test arguments and an optional assert message. When a test fails, the assert halts the routine and sends the error message to stdout.

There are three sets of assert methods. In the first set (Table 1) are the basic Boolean asserts, which fire on a True or False result.

Assert Complement Assert Operation
assertTrue(a, M) assertFalse(a, M) a = True; a = False
assertEqual(a, b, M) assertNotEqual(a, b, M) a = b; a ≠ b
assertIs(a, b, M) assertIsNot(a, b, M) a is b; a is not b
assertIsNone(a, M) assertIsNotNone(a, M) a = nil; a ≠ nil
AssertIsInstance(a, b, M) AssertIsNotInstance(a, b, M) isinstance(a,b);
not isinstance(a,b)

Table 1: Basic asserts in unittest.

To check for just a True or False, use assertTrue() or assertFalse(), as in Listing Three:

Listing Three: Checking for True or False.

1
2
3
4
5
6
self.assertTrue(argState, "foobar() gave back a False")
# -- fires when the instance method foobar() returns a True
self.assertFalse(argState)
# -- fires when foobar() returns a False
# Notice this one does not supply an assert message

To check whether two arguments are the same, use assertEqual() and assertNotEqual() as in Listing Four. These last two asserts check the arguments’ values, as well as their data types.

Listing Four: Checking arguments.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
argFoo = "narf"
argBar = "zort"
self.assertEqual(argFoo, argBar, "These are not the same")
# -- this assert will fail
self.assertNotEqual(argFoo, argBar, "These are the same")
# -- this assert will succeed
argFoo = 123
argBar = "123"
self.assertEqual(argFoo, argBar, "These are not the same")
# -- this assert will fail

To check if the arguments are the same objects, use assertIs() and assertIsNot(). Like assertEqual() and assertNotEqual(), these two asserts examine both argument values and type. To check if an argument is an instance of a specific class, use assertIsInstance() and assertIsNotInstance() as in Listing Five.

Listing Five: Checking if an argument is an instance of a specific class.

1
2
3
4
5
6
7
8
9
argFoo = Bar()
# checking against class Bar
self.assertIsInstance(argFoo, Bar, "The object is not an instance of class Bar")
# -- this assert will succeed
# checking against class Foo
self.assertIsNotInstance(argFoo, Foo, "The object is an instance of class Foo")
# -- this assert will fail

Both asserts get a class name as a second argument. Both behave similarly to the library function isInstance(). Finally, to check for a nil, use assertIsNone() and assertIsNotNone().

The second set of asserts are comparative (see Table 2).

Assert Complement Assert Operation
assertGreater(a, b, M) assertLess(a, b, M) a > b; a < b
assertGreaterEqual(a, b, M) assertLessEqual(a, b, M) a ≥ b; a ≤ b
assertAlmostEqual(a, b, n, M) assertNotAlmostEqual(a, b, n, M) round(a-b, n) = 0
round)a-b, n) ≠ 0
assertItemsEqual(a, b, M) none sort(a) = sort(b);
sort(a) ≠ sort(b)

Table 2: The comparative assertions.

To check whether one argument is greater or less than another, use assertGreater() and assertLess() as in Listing Six.

Listing Six: Greater or Less.

1
2
3
4
5
6
7
8
argFoo = 123
argBar = 452
self.assertGreater(argFoo, argBar, "Foo is less than Bar")
# -- this assert will fail
self.assertLess(argFoo, argBar, "Foo is greater than Bar")
# -- this assert will succeed

To check whether one argument is greater, less than or equal to the other, use assertGreaterEqual() and assertLessEqual(). The arguments in these four asserts can be a primitive (integer, float, character), a sequence, or a collection. Both arguments, however, must have the same data type.

To do a tolerance check, use assertAlmostEqual() and assertAlmostNotEqual(). These two asserts round off the arguments to a fixed number of decimal places before comparing their values. The number of decimal places is 7 by default. To change it, pass the new number with a places label.

To compare two sequences, use assertItemsEqual(). Its two arguments must be the same sequence type (list, tuple, set, and so on). Note that this assert sorts the sequence items prior to comparison.

Third set of asserts (Table 3) work with collection objects such as dictionaries, lists, sets, and tuples.

Assert Complement Assert Operation
assertIn(a, b, M) assertNotIn(a, b, M) a in b; a not in b
assertDictContainsSubset(a, b, M) none a has b
assertDictEqual(a, b, M) none a = b
assertListEqual(a, b, M) none a = b
assertSetEqual(a, b, M) none a = b
assertSequenceEqual(a, b, M) none a = b
assertTupleEqual(a, b, M) none a = b
assertMultilineEqual(a, b, M) none a = b

Table 3: Assertions for collections.

Arguments must be a collection type. Some assertions need not use arguments of the same type. All but one assert in this set have no complements.

To check whether one dictionary has some of the key/value pairs as the other, use assertDictContainsSubset() as shown in Listing Seven.

Listing Seven.

1
2
3
4
5
6
7
8
9
10
11
argBar = {'narf':456, 'poink':789}
self.assertDictContainsSubset(argFoo, argBar, "Foo does not have Bar")
# -- this assert will succeed
self.assertDictContainsSubset(argBar, argFoo, "Foo does not have Bar")
# -- this assert will fail
argBar = {'narf':456, 'egad':789}
self.assertDictContainsSubset(argFoo, argBar, "Foo does not have Bar")
# -- this assert will also fail

The first argument serves as reference; the second holds the pairs in question. To check if both dictionaries have the same key/value pairs, use assertDictEqual(). Each pair must have the same key labels and data values. How the pairs are arranged is irrelevant.

To check two sequence objects, use assertSequenceEqual(). Sequence types include lists, sets, tuples, even strings. For sequence objects to be same, they must have the same number of data items. The items must have the same value and they must be arranged the same. The sequence type must also be the same.

To check if two list objects are the same, use assertListEqual(). Both objects must have the same number of items. Those items must have the same values and the same order. To check two set objects, use assertSetEqual(). As with lists, both set objects must have the same number of items and item values. But item order is irrelevant, because set objects arrange their items internally.

Finally, to check if two tuples are the same, use assertTuplesEqual(). To check if two strings are the same, use assertMultilineEqual(). And to find out if one string is or is not inside another string, use assertIn() and assertNotIn().

This third set of asserts has one interesting behavior. If the collection objects are not equal, the assert will report the differences between the objects. It also adds this diff result to the assert message, if one is available.

Preparing a Test Suite

Usually, a few test cases are enough for your testing needs of a single class. But what if you have a dozen or more tests cases on hand — some you wrote yourself, some written by others? What if you want only a subset of test routines to run from the same test case? What if you want to refactor your test routines for easier cataloging and distribution? For these situations, you might need a test suite.

Figure 4 shows the basic structure of the TestSuite class.

Python Unit Tests
Figure 4: The TestSuite class.

There are three sets of instance methods. The first set lets us add test cases to the suite. To add a single test case, use the addTest() method as shown in Listing Eight.

Listing Eight.

1
2
3
4
5
6
7
8
9
10
class FooTest(unittest.TestCase):
    def testA(self):
        """Test routine A"""
        print "Running test A"
# creating a new test suite
newSuite = unittest.TestSuite()
# adding a test case
newSuite.addTest(unittest.makeSuite(FooTest))

Pass the test case (here being FooTest) to the instance method using the convenience function makeSuite(). You can also use makeSuite() to “convert” the test case into a test suite.

newSuite = unittest.makeSuite(FooTest)

To add a specific test routine, pass the test case object to the suite through the same addTest() method. Then pass the name of the test routine to the test case’s constructor. Notice the routine name is passed as a string.

newSuite.addTest(FooTest("testA"))

You can also use the same method to add two or more test routines to the same suite:

newSuite.addTest(FooTest(“testA”))
newSuite.addTest(FooTest(“testB”))
#…

To add two or more test cases, gather the names of the test cases into a list as shown in Listing Nine.

Listing Nine.

1
2
3
4
5
6
7
8
9
testList = [FooTest, BarTest]
testLoad = unittest.TestLoader()
caseList = []
for testCase in testList:
    testSuite = testLoad.loadTestsFromTestCase(testCase)
    caseList.append(testSuite)
newSuite = unittest.TestSuite(caseList)

Parse the list with a for loop, then use a TestLoader object (testLoad) to read each case. Add the read cases to a second list (caseList). Then create the TestSuite object (newSuite), passing to the class constructor the list object caseList.

Suppose you want to add another test suite to the suite. Simply pass the other suite to the addTest() method — no need to reuse the makeSuite() function to prepare the added suite.

fooSuite = unittest.TestSuite()
fooSuite.addTest(unittest.makeSuite(FooTest))
#...
barSuite = unittest.TestSuite()
barSuite.addTest(fooSuite)

The second set of methods run the tests in the test suite. The run() method takes a TestResult object as input, while debug() does not. But debug() does let an external debugger monitor the ongoing test.

Finally, the last set contains the method countTestCases(). This method returns the number of test cases held in the suite.

testCount = fooSuite.countTestCases()

Running the Tests

You have two ways to run your unit tests. If the test script is a single file with one or more test cases, add these lines after the last test case.

if name == "main":
unittest.main()

The if block detects how the file is acted upon. If the file is imported into another file, the macro __name__ is unchanged. If the file is executed directly, either from the text editor, from another script, or from the command-line, the __name__ macro resolves into "__main__", and the class method main() gets called. This in turn invokes the run() methods of every test case defined or imported by the script file.

If the script file defines a test suite, first create an instance of TextTestRunner. Then pass the test suite object to the runner’s run() method.

fooRunner = unittest.TextTestRunner()
fooRunner.run(fooSuite)

Regardless of approach, test cases and their routines run in alphanumeric order. BarTest runs before FooTest, FooTest before Test123, and test_12() before test_A(). Consider the test script in Listing Nine. In it, you have two test cases: BarTest and FooTest. BarTest has three test routines; FooTest has two.

Figure 5 shows how these two test cases run. BarTest runs first, FooTest second.

Python Unit Tests
Figure 5: BarTest and FooTest.

The test routines in BarTest run in the order from A to C. Those in FooTest run from 1 to 2. The same setUp() and tearDown() methods run before and after each test routine. But the BarTest routines have their own setUp() and tearDown(). The same also holds for the FooTest routines.

Finally, you have the option to skip or fail some of the test routines. To skip a routine unconditionally, use the class method unittest.skip() as shown in Listing Ten.

Listing Ten: Skipping a routine.

1
2
3
4
5
6
@unittest.skip("Skip over the entire test routine")
def testB():
    """Test routine B"""
    # the following code will not run
    fooA = narf()
    self.assertNotEqual(fooA, 123)

This method gets one argument: a log message describing the reason for the skip. Place the method call before the test routine, and make sure to prefix the call with a @ token. Alternatively, use the instance method skipTest(), which you can place inside the test routine as in Listing Eleven.

Listing Eleven.

1
2
3
4
5
6
"""Test routine B"""
self.skipTest("Skip over the rest of the routine")
# the following code will not run
fooA = narf()
self.assertNotEqual(fooA, 123)

 

To skip a test routine conditionally, use the class methods unittest.skipIf() and unittest.skipUnless() as in Listing Twelve:

Listing Twelve.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@unittest.skipIf(self.fooC > 456, "Skip over this routine")
def testB():
    """Test routine B"""
    # the following code will run only when fooC is less
    # than or equal to 456
    fooA = narf()
    self.assertNotEqual(fooA, 123)
@unittest.skipUnless(self.fooC > 456, "Skip over this routine")
def testC():
    """Test routine C"""
    # the following code will run only when fooC is
    # greater than 456
    fooA = zort()
    self.assertNotEqual(fooA, 123)

The first method causes a skip when a condition is met, the second when a condition is not met. Both get two arguments: the condition and the reason for the skip. Both must be placed before the test routine. The condition may involve a class property or another class method.

To fail a test routine, use the instance method fail() as in Listing Thirteen:

Listing Thirteen.

1
2
3
4
5
6
7
8
9
10
11
def testB():
    """Test routine B"""
    self.fail("Force this routine to fail.")
    
    # the following code will not run
    fooA = narf()
    self.assertNotEqual(fooA, 123)
def testC():
    """Test routine C"""
    print "This routine still runs after testB."

This method takes a log message explaining the reason for failure. Like skipTest(), the fail() method goes inside the test routine. Code placed after the call to fail() will not run, but test routines after the failed routine still get to run.

Viewing the Test Results

There are two possible forms of output from the TextTestRunner: console text or a TestResult object. First, let’s look at the console output, which shows each test’s result. You can control this output by passing three optional arguments to the class constructor.

unittest.TextTestRunner(stream=sys.stderr, descriptions=True, verbosity=1)

The first argument (labelled stream) sets the output destination. This defaults to sys.stderr if one is not specified. Next argument (labelled descriptions) controls how errors and failures are reported. Passing a True (default) tells the runner to name those routines that erred, failed, or skipped. Passing a False tells it not to.

The last constructor argument (labelled verbosity) sets the level of detail. There are three possible levels. For a verbosity of 0, the results show only the number of executed tests and the final outcome of those tests. For a verbosity of 1, the results marks a successful test with a dot, a failed one with an F, a skipped one with an s, and an erroneous one with an E. And for a verbosity of 2, the results lists each test case and test routine, plus the outcome of each routine.

To demonstrate, let’s run the test script in Listing Fourteen:

Listing Fourteen: Test script.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import sys
import unittest
class FooTest(unittest2.TestCase):
    """Sample test case"""
    
    # preparing to test
    def setUp(self):
        """ Setting up for the test """
        print "FooTest:setUp_"
    
    # ending the test
    def tearDown(self):
        """Cleaning up after the test"""
        print "FooTest:tearDown_"
    
    # test routine A
    #@unittest2.skip("FooTest:test_A:skipped")
    def test_A(self):
        """Test routine A"""
        self.skipTest("FooTest:test_A:skipped")
        print "FooTest:test_A"
    
    # test routine B
    def test_B(self):
        """Test routine B"""
        fooA = 123
        fooB = 234
        self.assertEqual(fooA, fooB, "A is not equal to B")
        print "FooTest:test_B"
    
    # test routine C
    def test_C(self):
        """Test routine C"""
        fooA = 123
        self.assertEqual(fooA, fooB, "A is not equal to B")
        print "FooTest:test_C"
    
    # test routine D
    def test_D(self):
        """Test routine D"""
        self.fail("FooTest:test_D:fail_")
        print "FooTest:test_D"
# Run the test case
if __name__ == '__main__':
    fooSuite = unittest.TestLoader().loadTestsFromTestCase(FooTest)

If you create the test runner as follows:

fooRunner = unittest.TextTestRunner(description=True)
fooRunner.run(fooSuite)

The results appear as shown next:

sFEF
================================================================
ERROR: test_C (__main__.FooTest)
Test routine C
----------------------------------------------------------------

================================================================
FAIL: test_B (__main__.FooTest)
Test routine B
----------------------------------------------------------------

================================================================
FAIL: test_D (__main__.FooTest)
Test routine D
----------------------------------------------------------------

----------------------------------------------------------------
Ran 4 tests in 0.004s

FAILED (failures=2, errors=1, skipped=1) 

But if you create the runner as follows:

fooRunner = unittest.TextTestRunner(description=False)

The docstr comment line from each test routine will not be included.

The console output above has a verbosity level of 1. It starts with the line sFEF, which states two failed tests, one skipped, and one erroneous test. But suppose you created the test runner by typing

fooRunner = unittest.TextTestRunner(verbosity=0)

Then, the sFEF line will not appear. If you create the test runner by typing

fooRunner = unittest.TextTestRunner(verbosity=2)

Then the console output appears as:

test_A (__main__.FooTest)
Test routine A ... skipped 'FooTest:test_A:skipped'
test_B (__main__.FooTest)
Test routine B ... FAIL
test_C (__main__.FooTest)
Test routine C ... ERROR
test_D (__main__.FooTest)
Test routine D ... FAIL

================================================================
ERROR: test_C (__main__.FooTest)
Test routine C
----------------------------------------------------------------

================================================================
FAIL: test_B (__main__.FooTest)
Test routine B
----------------------------------------------------------------

================================================================
FAIL: test_D (__main__.FooTest)
Test routine D
----------------------------------------------------------------

----------------------------------------------------------------
Ran 4 tests in 0.009s

FAILED (failures=2, errors=1, skipped=1)

Note that the sFEF line is replaced by four pairs of lines, each pair naming the test case and routine, the final test state, the docstr comment of each routine, and any assert messages.

The second type of output is the TestResults object. This one is returned by the runner object after all the tests have run:

fooResult = fooRunner.run(fooSuite)

The TestResult object has two sets of property accessors (Figure 6).

Python Unit Tests
Figure 6: The TestResult object (in part).

This is not a complete set of accessors, but these are ones you will most likely use. The first set returns a list of tuples. Each tuple reveals how each test routine fared when executed. The errors accessor lists identified routines that raised an exception. Each tuple has the name of the test case and routine, the location of the test script, the line position of the error, a trace-back, and a reason for the error.

The failures accessor lists test routines that failed. Its tuples contain the same information as tuples from the errors accessor. The skipped accessor lists routines that were skipped, conditionally or not. Its tuples name the test case and routine, and give the reason for the skip.

The second set of accessors provides additional data. testsRun gives the number of test routines that ran, regardless of outcome. And wasSuccessful() returns a True if all routines ran without problems, False if at least one routine had a problem. Notice this last accessor is written as a function.

Listing Fifteen demonstrates how the TestResult object works.

Listing Fifteen.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import sys
import unittest
class FooTest(unittest.TestCase):
    """Sample test case"""
    
# Run the test case
if __name__ == '__main__':
    fooSuite = unittest.TestLoader().loadTestsFromTestCase(FooTest)
    
    fooRunner = unittest.TextTestRunner()
    fooResult = fooRunner.run(fooSuite)
    
    print
    print "---- START OF TEST RESULTS"
    print fooResult
    print
    print "fooResult::errors"
    print fooResult.errors
    print
    print "fooResult::failures"
    print fooResult.failures
    print
    print "fooResult::skipped"
    print fooResult.skipped
    print
    print "fooResult::successful"
    print fooResult.wasSuccessful()
    print
    print "fooResult::test-run"
    print fooResult.testsRun
    print "---- END OF TEST RESULTS"
    print

This script uses the same FooTest case defined in Listing Fourteen. After it invokes the run() method in the runner object fooRunner, the script stores the results into the local fooResults. Then it invokes each accessor and prints the test result on the console window.

Here are the test results returned by fooRunner:

---- START: Test Results:
<unittest2.runner.TextTestResult run=4 errors=1 failures=2>

fooResult::errors
[(<__main__.FooTest testMethod=test_C>, 'Traceback (most
recent call last):\n  File "/Volumes/Projects/Pro_Articles/_ddj/
18_pyUnitTest/ddj18_code/foo_testRun.py", line 49, in test_C\n    
self.assertEqual(fooA, fooB, "A is not equal to B")\nNameError: 
global name \'fooB\' is not defined\n')]

fooResult::failures
[(<__main__.FooTest testMethod=test_B>, 'Traceback (most 
recent call last):\n  File "/Volumes/Projects/Pro_Articles/_ddj/
18_pyUnitTest/ddj18_code/foo_testRun.py", line 41, in test_B\n    
self.assertEqual(fooA, fooB, "A is not equal to B")
\nAssertionError: 123 != 234 : A is not equal to B\n'), 
(<__main__.FooTest testMethod=test_D>, 'Traceback (most 
recent call last):\n  File "/Volumes/Projects/Pro_Articles/_ddj/
18_pyUnitTest/ddj18_code/foo_testRun.py", line 55, in test_D\n    
self.fail("FooTest:test_D:fail_")\nAssertionError: 
FooTest:test_D:fail_\n')]

fooResult::skipped
[(<__main__.FooTest testMethod=test_A>, 'FooTest:test_A:skipped')]

fooResult::successful?
False

fooResult::test-run
4

The second line summarizes the results. It shows the total number of test routines and how many routines have erred or failed. The paragraph below it reveals the erroneous routine: test_C(). It also reveals the cause of the error: the undefined variable fooB.

The next clump of text reveals the failed routines: test_B() and test_D(). It reveals why test_B() failed: two unequal values passed to assertEqual(). And it reveals that test_D() has explicitly called the instance method fail().

Below that is shown the skipped routine, test_A(). The next line shows what problems were encountered. And the last two lines report that a total of four test routines ran, confirming what was reported initially.

Conclusion

Python has substantial resources to enable unit testing. In this article, I looked into the unittest module and examined those classes essential for unit testing. I showed how to create a test case, how to design the test routines, and how to gather several test cases into one test suite.

The unittest module can do more than just run basic tests. With it, we can design tests that focus on exceptions or tests that do pattern matching. We can load and execute tests stored in separate files. We can even design tests that use simulated objects (known as mocks). But these are topics for a later article. Meanwhile, the “Recommended References” can provide additional guidance on these more-advanced features.

 

This Article Referenced from (http://www.drdobbs.com/testing/unit-testing-with-python)

For More Info on Python UnitTest

Recommended References

Test-Driven Development in Python, Jason Diamond. ONLamp.com/O’Reilly Publishing.

Introduction to unittest, Michael Foord. Voidspace.

unittest: Automated testing framework, Doug Hellman. PyMOTW.

unittest: Unit testing framework, Python 2.7.6 documentation.

Testing Your Code, Kenneth Reitz. The Hitchhiker’s Guide to Python.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s