Unittest
Unittest is an test frameowrk written for python. Unittest supports some important concepts in an object-oriented way.
Terminology:
- test fixture
-- A test fixture represents the preparation needed to perform one or more tests, and any associated cleanup actions. This may involve, for example, creating temporary or proxy databases, directories, or starting a server process.
- test case
-- A test case is the individual unit of testing. It checks for a specific response to a particular set of inputs. unittest provides a base class, TestCase, which may be used to create new test cases.
- test suite
-- A test suite is a collection of test cases, test suites, or both. It is used to aggregate tests that should be executed togethe
- test runner
-- A test runner is a component which orchestrates the execution of tests and provides the outcome to the user. The runner may use a graphical interface, a textual interface or something else.
Basic Example
Here is a short script to test three string methods:
import unittest
class TestStringMethods(unittest.TestCase):
def test_upper(self):
self.assertEqual('foo'.upper(), 'FOO')
def test_isupper(self):
self.assertTrue('FOO'.isupper())
self.assertFalse('Foo'.isupper())
def test_split(self):
s = 'hello world'
self.assertEqual(s.split(), ['hello', 'world'])
# check that s.split fails when the separator is not a string
with self.assertRaises(TypeError):
s.split(2)
if __name__ == '__main__':
unittest.main()
A testcase is created by subclassing unittest.TestCase
. The three individual tests are defined with methods whose names start with the letters test. This naming convention informs the test runner about which methods represent tests.
The crux of each test is a call to assertEqual()
to check for an expected result; assertTrue()
or assertFalse()
to verify a condition; or assertRaises()
to verify that a specific exception gets raised.
The final block shows a simple way to run the tests. unittest.main()
provides a command-line interface to the test script.
Command line interface
The unittest module can be used from the command line to run tests from modules, classes or even individual test methods:
python -m unittest test_module1 test_module2
python -m unittest test_module.TestClass
python -m unittest test_module.TestClass.test_method
Test modules can be specified by file path as well:
python -m unittest tests/test_something.py
When executed without arguments Test Discovery is started:
python -m unittest
Test Discovery
Unittest supports simple test discovery. In order to be compatible with test discovery, all of the test files must be modules or packages (including namespace packages) importable from the top-level directory of the project
cd project_directory
python -m unittest discover
As a shortcut, python -m unittest
is the equivalent ofpython -m unittest discover
.
Organizing test code
The basic building blocks of unit testing are test cases — single scenarios that must be set up and checked for correctness. In unittest, test cases are represented by unittest.TestCase instances.
import unittest
class DefaultWidgetSizeTestCase(unittest.TestCase):
def setUp(self):
self.widget = Widget('The widget')
def test_default_widget_size(self):
widget = Widget('The widget')
self.assertEqual(widget.size(), (50, 50))
def tearDown(self):
self.widget.dispose()
Note that in order to test something, we use one of the assert*() methods provided by the TestCase base class. setUp()
is an built in method that creates an enviorement for that test case. imilarly, we can provide a tearDown() method that tidies up after the test method has been run.
Re-using old test code
def testSomething():
something = makeSomething()
assert something.name is not None
# ...
one can create an equivalent test case instance as follows, with optional set-up and tear-down methods:
testcase = unittest.FunctionTestCase(testSomething,
setUp=makeSomethingDB,
tearDown=deleteSomethingDB)
Skipping tests and expected failures
Skipping a test is simply a matter of using the skip() decorator
class MyTestCase(unittest.TestCase):
@unittest.skip("demonstrating skipping")
def test_nothing(self):
self.fail("shouldn't happen")
or skill whole test case
@unittest.skip("showing class skipping")
class MySkippedTestCase(unittest.TestCase):
def test_not_run(self):
pass
Expected failures use the expectedFailure() decorator.
class ExpectedFailureTestCase(unittest.TestCase):
@unittest.expectedFailure
def test_fail(self):
self.assertEqual(1, 0, "broken")
Classes and functions
This just shows the api reference of all of the functions in unittest
. Link: https://docs.python.org/3/library/unittest.html#classes-and-functions