We use python's built-in vanilla unittest module to write tests. For most use cases, this package provides us with sufficient tools to get the job done
In general, we want the directory that holds the tests to be of the same structure as the packages and modules we intend to test (i.e packageA).
TestCase
The smallest unit of testing is an instance of unittest.TestCase. This represents a single test case/or a few closely related ones.
test_A.py
from packageA.A import Aimport unittestclassTestA(unittest.TestCase):defsetUp(self):...# Code runs before each test_* is executeddeftest_A_like_this(self):...# Write asserts heredeftest_A_like_this_too(self):...# Write asserts here toodeftearDown(self):...# Code runs after each test_* is executedif__name__=='main':# Runs all test cases within this module unittest.main()
Some pointers:
setUp & tearDown are called before & after each test method is called. (Called each time for each test_* method)
test methods must be of the form test_* to be run by unittest
A unittest.TestCase can also implement runTest as opposed to test_* methods if it is only implementing one test
Discovery (TestLoader)
We can group multiple TestCases together into TestSuites and run them (This is usually what we want to do). We want to write unittests without having to worry to import and run them as well. TestLoaders make this very easy.
The unittest.TestLoader has a discover method that auto-detects TestCases within a directory and adds them all to a suite.
Let's assume that our folder structure looks like this:
We can load and run all tests within the /tests directory from run_tests.py in the following manner:
Some pointers about TestLoader:
If you want to define your own way to search for test_cases you can make your own TestLoader that overrides discover
top_level_dir should be passed in as '.'. Otherwise it sets the start_dir as the top_level_dir, adds this to sys.path and can mess up imports across the app