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)