I would like to setup unit tests for a python application. There are many ways to do this, including doctest and unittest, as well as 3rd-party frameworks that leverage python’s unittest, such as pytest and nose.
I found the plain-old unittest framework to be the easiest to work with, although I often run into questions about how best to organize tests for various sized projects. Regardless of the size of the projects, I want to be able to easily run all of the tests, as well as run specific tests for a module.
The standard naming convention is “test_ModuleName.py”, which would include all tests for the named module. This file can be located in the same directory (package) as the module, although I prefer to keep the tests in their own subdirectory (which can easily be excluded from production deployments).
In other words, I end up with the following:
package/ - __init__.py - Module1.py - Module2.py - test/ - all_tests.py - test_Module1.py - test_Module2.py
Each of the test_*.py files looks something like this:
#!/usr/bin/env python # vim: set tabstop=4 shiftwidth=4 autoindent smartindent: import os, sys, unittest ## parent directory sys.path.insert(0, os.path.join( os.path.dirname(__file__), '..' )) import ModuleName class test_ModuleName(unittest.TestCase): def setUp(self): ''' setup testing artifacts (per-test) ''' self.moduledb = ModuleName.DB() def tearDown(self): ''' clear testing artifacts (per-test) ''' pass def test_whatever(self): self.assertEqual( len(self.moduledb.foo()), 16 ) if __name__ == '__main__': unittest.main()
With this approach, the tests can be run by all_tests.py, or I can run the individual test_ModuleName.py.
The all_tests.py script also must add the parent directory on the path, i.e.,
#!/usr/bin/env python # vim: set tabstop=4 shiftwidth=4 autoindent smartindent: import sys, os import unittest ## set the path to include parent directory sys.path.insert(0, os.path.join( os.path.dirname(__file__), '..' )) ## run all tests loader = unittest.TestLoader() testSuite = loader.discover(".") text_runner = unittest.TextTestRunner().run(testSuite)