unittest

unittest basically provides what JUnit does for Java. It offers a base class called TestCase, which has an extensive set of methods to verify the output of function calls and statements. It is the most basic and common Python testing library and often serves as a basis for more complex and elaborate testing frameworks.

This module was created with unit tests in mind, but you can use it to write other kinds of tests. It is even possible to use it in acceptance testing flows with user interface layer integration, as some testing libraries provide helpers to drive tools such as Selenium on top of unittest.

Writing a simple unit test for a module using unittest is done by subclassing TestCase and writing methods with the test prefix. The example test module based on usage examples from the Test-driven development principles section will look like this:

import unittest 
 
from primes import is_prime 
 
 
class MyTests(unittest.TestCase): 
    def test_is_prime(self): 
        self.assertTrue(is_prime(5)) 
        self.assertTrue(is_prime(7)) 
 
        self.assertFalse(is_prime(8)) 
        self.assertFalse(is_prime(0)) 
        self.assertFalse(is_prime(1)) 
 
        self.assertFalse(is_prime(-1)) 
        self.assertFalse(is_prime(-3)) 
        self.assertFalse(is_prime(-6)) 
 
 
if __name__ == "__main__": 
    unittest.main()

The unittest.main() function is the utility that allows you to make the whole module executable as a test suite, as follows:

$ python test_is_prime.py -v
test_is_prime (__main__.MyTests) ... ok

--------------------------------------------------------------
Ran 1 test in 0.000s

OK  

The unittest.main() function scans the context of the current module and looks for classes that subclass TestCase. It instantiates them, then runs all methods that start with the test prefix.

A good test suite follows common and consistent naming conventions. For instance, if the is_prime function is included in the primes.py module, the test class could be called PrimesTests and put into the test_primes.py file, as follows:

import unittest 
 
from primes import is_prime 
 
 
class PrimesTests(unittest.TestCase): 
    def test_is_prime(self): 
        ...

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

From there, every time the primes module evolves, the test_primes module gets more tests.

In order to work, the test_primes module needs to have the primes module available in the context. This can be achieved either by having both modules in the same package or by adding a tested module explicitly to the Python path. In practice, the develop command of setuptools is very helpful here (see Chapter 7, Writing a Package).

Running tests over the whole application presupposes that you have a script that builds a test campaign out of all test modules. unittest provides a TestSuite class that can aggregate tests and run them as a test campaign, as long as they are all instances of TestCase or TestSuite.

In Python's past, there was a convention that the test module provides a test_suite function that returns a TestSuite. This function would be used in the __main__ section, when the module is called in command prompt, or automatically collected by a test runner, as follows:

import unittest 
 
from primes import is_prime 
 
 
class PrimesTests(unittest.TestCase): 
    def test_is_prime(self): 
        self.assertTrue(is_prime(5)) 
 
        self.assertTrue(is_prime(7)) 
 
        self.assertFalse(is_prime(8)) 
        self.assertFalse(is_prime(0)) 
        self.assertFalse(is_prime(1)) 
 
       self.assertFalse(is_prime(-1)) 
        self.assertFalse(is_prime(-3)) 
        self.assertFalse(is_prime(-6)) 
 
 
class OtherTests(unittest.TestCase): 
    def test_true(self): 
        self.assertTrue(True)

def test_suite(): """builds the test suite.""" suite = unittest.TestSuite() suite.addTests(unittest.makeSuite(PrimesTests)) suite.addTests(unittest.makeSuite(OtherTests)) return suite if __name__ == '__main__': unittest.main(defaultTest='test_suite')

Running this module from the shell will print the following test campaign output:

$ python test_primes.py -v
test_is_prime (__main__.PrimesTests) ... ok
test_true (__main__.OtherTests) ... ok

----------------------------------------------------------------------
Ran 2 tests in 0.001s

OK

The preceding approach was required in the older versions of Python when the unittest module did not have proper test discovery utilities. Usually, the running of all tests was done by a global script that browsed the code tree, looking for tests to run. This process is often called test discovery, and will be covered more extensively later in this chapter. For now, you should only know that unittest provides a simple command that can discover all tests from modules and packages that are named with a test prefix, as follows:

$ python -m unittest -v
test_is_prime (test_primes.PrimesTests) ... ok
test_true (test_primes.OtherTests) ... ok

----------------------------------------------------------------------
Ran 2 tests in 0.001s

OK  

If you use the preceding command, then there is no need to manually define the __main__ sections and invoke the unittest.main() function.