Test theory:
- Test fixture: this is the test preparation before tests and any associated cleanup actions.
- Test case: this is the most fundamental test unit.
- Test suite: this is a collection of test cases and/or test suites.
- Test runner: this is the most outer part of the test system, is used to orchestrate the execution of tests and to provide the outcomes to the user.
How to run unittest from command-line?
Here is an example of running unittest from command-line for the project Lux:
python -m unittest discover -s tests -p . -f -v
This will be explained in more details with further more options.
-m: run the 'unittest' library module as a script.
-v: verbose
-f (--failfast): stop the test run on the first error or failure.
-b (--buffer): stdout and stderr streams are bufferred during the test run. It will be discarded for passing tests and echo normally for test fail or error.
-c (--catch): First Control-C waits current running test and reports after its completion. A second Control-C raises the normal KeyboardInterrupt exception.
--locals: show local variables in trackbacks.
-s and -p: are discovery mode parameters.
-f (--failfast): stop the test run on the first error or failure.
-b (--buffer): stdout and stderr streams are bufferred during the test run. It will be discarded for passing tests and echo normally for test fail or error.
-c (--catch): First Control-C waits current running test and reports after its completion. A second Control-C raises the normal KeyboardInterrupt exception.
--locals: show local variables in trackbacks.
-s and -p: are discovery mode parameters.
Accepted input file list:
The unittest module can be run from the following different manner from a command-line environment.
Class or Module:
python -m unittest test_module1 test_module2python -m unittest test_module.TestClasspython -m unittest test_module.TestClass.test_method
File with path:
python -m unittest tests/test_something.py
Test Discovery:
python -m unittestHere no input arguments are provided. This lead unittest module into a discovery mode, in which unittest searches test case class by itself in the given or current directory (by default).
Test Discovery
Running requirements:
All of the test files must be modules or packages (including namespaces packages) importable from the top-level directory of the project!!! (this can be denoted by -t option)
Arguments options:
-s (--start-directory): Directory to start discovery (. default)
-p (--pattern): Pattern to match test files (test*.py default)
-t (--top-level-directory): Top level directory of project (default to start directory)
Prepare the basic test unit: a Test Case
Subclass of TestCase
import unittest
class DefaultWidgetSizeTestCase(unittest.TestCase): def test_default_widget_size(self): widget = Widget('The widget') self.assertEqual(widget.size(), (50, 50))
Test (test_default_widget_size) is labelled as failure if function assertEqual() raised an exception. Any other exceptions are labelled as errors.
import unittest
class WidgetTestCase(unittest.TestCase): def setUp(self): self.widget = Widget('The widget') def tearDown(self): self.widget.dispose()
setUp() and tearDown() are used to prepare and cleanup tests. They will be called for every single test.
If setUp() fails, the test case is labelled as failed.
If setUp() succeeded, tearDown() will be run whether the test function is succeeded or not.
To use the test suite:
def suite(): suite = unittest.TestSuite() suite.addTest(WidgetTestCase('test_default_widget_size')) suite.addTest(WidgetTestCase('test_widget_resize')) return suite
if __name__ == '__main__': runner = unittest.TextTestRunner() runner.run(suite())
FunctionTestCase
This is a method to reuse the old test code back from the dark ages without systematic testing components. This is where FuntionTestCase comes into consideration.FunctionTestCase is a subclass of the TestCase, which wraps an existing test function. Its flexibility makes the setUp() and tearDown() functions available to be provided:
def testSomething():
something = makeSomething()
assert something.name is not None
# ...
testcase = unittest.FunctionTestCase(testSomething,
setUp=makeSomethingDB,
tearDown=deleteSomethingDB)
Even though the FunctionTestCase provides an alternative method to construct a test case. But this is not a recommend solution.
Skip a test
The following decorators implement test skipping and expected failures:
@
unittest.
skip
(reason)¶- Unconditionally skip the decorated test. reason should describe why the test is being skipped.
@
unittest.
skipIf
(condition, reason)¶- Skip the decorated test if condition is true.
@
unittest.
skipUnless
(condition, reason)¶- Skip the decorated test unless condition is true.
@
unittest.
expectedFailure
¶- Mark the test as an expected failure. If the test fails when run, the test is not counted as a failure.
- exception
unittest.
SkipTest
(reason)¶ - This exception is raised to skip a test.
setUp() and tearDown() will not be run for skipped tests. setUpClass() and tearDownClass() will not be called for skipped test classes.
Subtest
This is specifically for iteration tests, where the test is commonly terminated after the first failure, which provide no obvious reason. The definition of the subtest would keep the iterative tests running to the end to show the abnormality along the whole iterative process.
Here is pretty much the most background of using Python unittest module. Most of the above content is from the Python Manual. Please refer it for more details.