/documentations/python_libraries/testing/unittest/

Unittest

Introduction

The Python unit testing framework, sometimes referred to as PyUnit, is a Python language version of JUnit, by Kent Beck and Erich Gamma. JUnit is, in turn, a Java version of Kent's Smalltalk testing framework. Each is the de facto standard unit testing framework for its respective language (see docs)

Hence the right place to get started is Kent Beck's original paper. The basic pattern introduced in this paper and shared by unittest is the following:

A test fixture represents the preparation needed to perform one or more tests, and any associate cleanup actions. This may involve, for example, creating temporary or proxy databases, directories, or starting a server process. *

A test case is the smallest unit of testing. It checks for a specific response to a particular set of inputs. unittest provides a base class, TestCase, which may be used to create new test cases. *

A test suite is a collection of test cases, test suites, or both. It is used to aggregate tests that should be executed together. *

A test runner is a component which orchestrates the execution of tests and provides the outcome to the user. The runner may use a graphical interface, a textual interface, or return a special value to indicate the results of executing the tests. *

Example

The examples below should give an idea on how the unittest module can be used. They are not meant as good test examples, but rather as patterns to quickly get started writing own test case classes. For good unittest examples simply look at the python libraries at: <path to libraries>/test/test_*.py. To find the path to python, type import sys; print sys.path in the python shell. To find test files on *nix systems, type find /usr/lib/python2.7/ -name *test_*.py in a terminal.

Example 1: test case

"""
Test case for fraction
file: test_fraction.py
"""
import unittest
from myfraction import fraction

class TestFrac(unittest.TestCase):
    def setUp(self):
        self.zero = fraction(0, 1)
        self.one  = fraction(1, 1)

    def test_return(self):
        f = fraction(2, 3)
        self.assertTrue(type(f) is tuple)

    def test_normalized_gcd(self):
        for n in range(1, 100):
            f = fraction(n, n)
            self.assertEqual(f, self.one)

    def test_normalized_sign(self):
        f = fraction(-1, -1)
        self.assertEqual(f, self.one)

    def test_zerodivision(self):
        with self.assertRaises(ZeroDivisionError):
            fraction(1, 0)

if __name__ == "__main__":
    unittest.main()

The code above is a simple test case for the fraction function below. A test case is a subclass of unittest.TestCase:

import unittest
[...]
class TestFrac(unittest.TestCase):
[...]

All methods of this class, whose names start with test are recognized as tests: test_return, test_normalized_gcd, test_normalized_sign and test_zerodivision. The actual tests are calls of assert functions. In the example above self.assertTrue(...) checks whether the argument is True, self.assertEqual(..., ...) checks whether the two arguments are equal and:

with self.assertRaises(<exception>): 
    <some code>

checks whether the given exception gets raised when executing some code. The full list can be found here.

The method setUp, is executed before each call of a test method. It is meant to set up a clean test environment (test fixture) before each call of a test method. Similarly there is a tearDown method, called after each test. Both methods have default implementations doing nothing.

"""
Implementation of gcd and fraction, 
to demonstrate the use of  the unittest module.
file: myfraction.py
"""

def gcd(a,b):
    """
    Returns the gcd of a and b
    """
    while 0 != b:
        (a, b) = (b, a%b)
    return a

def fraction(num, den):
    """
    Returns a fraction as tuple
    """
    if 0 == den: 
        raise ZeroDivisionError('fraction(%s, 0)' % num)
    else: 
        g = gcd(num, den)
        return (num//g, den//g)

The test case above can be executed by just executing python test_fraction.py, thanks to the lines:

if __name__ == "__main__":
    unittest.main()

An alternative is the command line interface:

python -m unittest -v test_fraction.TestFrac

Example 2: test suite

"""
Test suite for myfraction
file: test_myfraction.py
"""
import unittest
from test_gcd import TestGCD
from test_fraction import TestFrac

# Create a test suite for each test case

# GCD suite
suite_gcd = unittest.TestSuite()
# only add one test for gcd
suite_gcd.addTest(TestGCD('test_prime_products'))

# Fraction suite
# add all tests for fraction
suite_frac = unittest.TestLoader().loadTestsFromTestCase(TestFrac)

# Create a suite containing the two suits above
suite_myfraction = unittest.TestSuite([suite_gcd, suite_frac])

# Instantiate the test runner
runner = unittest.TextTestRunner()
# Run the runner
runner.run(suite_myfraction)

Test suites allow to organize the test code by aggregating test cases (and test suites) in test suites. The example above instantiates tree suites: suite_gcd, suite_frac and suite_myfraction. suite_gcd is first instantiated with uinittest.TestSuite(), and then a single test method is added with addTest(...). For suite_frac a test loader is used to load all test methods of the TestFrac test case:

suite_frac = unittest.TestLoader().loadTestsFromTestCase(TestFrac)

The two suites are then aggregated in one suite:

suite_myfraction = unittest.TestSuite([suite_gcd, suite_frac])

Finally a test runner is instantiated and then used to run the suite_myfraction.

"""
Test case for gcd
file: test_gcd.py
"""
import unittest
from myfraction import gcd

class TestGCD(unittest.TestCase):
    def test_prime_products(self):
        a = gcd(2*5*11*17*23*31*41*47*59,\
                3*7*13*17*19*29*37*43*53)
        self.assertEqual(a, 17)

    def test_type(self):
        self.assertTrue(type(gcd(1,1)) is int)

if __name__ == "__main__":
    unittest.main()