Posted on December 13, 2021 by Adrian Wyssmann ‐ 3 min read
As we know now, we need a unit test framework to do unit testing. If we have a look at Python, it comes with a unittest framework included:
The unittest unit testing framework was originally inspired by JUnit and has a similar flavor as major unit testing frameworks in other languages.
It offers the concepts I discussed here:
Let’s say we have a script example.py with the following content:
def simpleFunction(x,y):
if (5 <= x and y < 10):
return "do this"
else:
return "do that"We would create a test case which tests the different path of simpleFunction. We call the file test_example.py as follows
from example import *
import unittest
class SimpleFunctionTest(unittest.TestCase):
def test_dothistest(self):
self.assertAlmostEqual(simpleFunction(6,2), 'do this')
self.assertAlmostEqual(simpleFunction(5,9), 'do this')
def test_dothattest(self):
self.assertAlmostEqual(simpleFunction(5,10), 'do that')
self.assertAlmostEqual(simpleFunction(1,9), 'do that')
if __name__ == '__main__':
unittest.main()Some things which you need to know
test_classname.py - don’t use a . i.e classname.test.py as this will result in an error when executing the testsunittest as well as test object - in this case exampleunittest.TestCase.test_ - otherwise the functions will not be considered test casesunittest.main() when __name__ == '__main__ - this provides a command-line interface to the test scriptYou can call now the unit tests from the command line - we use -v to see the name of the test cases:
$ python3 example_test.py -v
test_dothattest (example_test.SimpleFunctionTest) ... ok
test_dothistest (example_test.SimpleFunctionTest) ... ok
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OKIf you have multiple files, you can also test discovery, which automatically detects tests.
$ python -m unittest -v
test_dothattest (test_example.SimpleFunctionTest) ... ok
test_dothistest (test_example.SimpleFunctionTest) ... ok
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OKOr
python -m unittest discover -v
test_dothattest (example_test.SimpleFunctionTest) ... ok
test_dothistest (example_test.SimpleFunctionTest) ... ok
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OKIt also offers
setUp() and
tearDown() methods, which will be executed before and after each test method.
You also can
skip tests using the
skip()-decorator or raise
skipTest. Here an example of the official documentation:
class MyTestCase(unittest.TestCase):
@unittest.skip("demonstrating skipping")
def test_nothing(self):
self.fail("shouldn't happen")
@unittest.skipIf(mylib.__version__ < (1, 3),
"not supported in this library version")
def test_format(self):
# Tests that work for only a certain version of the library.
pass
@unittest.skipUnless(sys.platform.startswith("win"), "requires Windows")
def test_windows_support(self):
# windows specific testing code
pass
def test_maybe_skipped(self):
if not external_resource_available():
self.skipTest("external resource not available")
# test code that depends on the external resource
passIf you want to group test cases together, you can build
TestSuites
import unittest
from example_test import *
def suite():
suite = unittest.TestSuite()
suite.addTest(SimpleFunctionTest('test_dothistest'))
suite.addTest(SimpleFunctionTest('test_dothattest'))
return suite
if __name__ == '__main__':
runner = unittest.TextTestRunner()
runner.run(suite())You can run this as follows:
python example_suite_test.py -v
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OKAnother interesting feature is
SubTests, which allows you to distinguish small differences for some parameters, using the same test method.
I recommend to read organize test code to better understand how you should organize your test code.
When writing code, it’s important you understand unit testing and the framework, the language of your choice offers. Whether it’s unittest for Python or JUnit for Java, they support the same important concepts, even so they differ in syntax.