Testing in Python
There are many ways to write unit tests in Python.
unittest⌗
Here the focus is living off the land with built-in unittest.
unittest
is both a framework and test runner, meaning it can execute your tests and return the results. In order to write unittest
tests, you must:
- Write your tests as methods within classes
- These
TestCase
classes must subclassunittest.TestCase
- Names of test functions must begin with
test_
- Import the code to be tested
- Use a series of built-in assertion methods
Basic example⌗
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()
Assertions⌗
The TestCase
class provides several assert methods to check for and report failures.
Assertion | Checks |
---|---|
assertEqual(a, b) |
a == b |
assertNotEqual(a, b) |
a != b |
assertTrue(x) |
bool(x) is True |
assertFalse(x) |
bool(x) is False |
assertIs(a, b) |
a is b |
assertIsNot(a, b) |
a is not b |
assertIsNone(x) |
x is None |
assertIsNotNone(x) |
x is not None |
assertIn(a, b) |
a in b |
assertNotIn(a, b) |
a not in b |
assertIsInstance(a, b) |
isinstance(a, b) |
assertNotIsInstance(a, b) |
not isinstance(a, b) |
Exceptions⌗
Validates an exception is raised when callable is called with any positional or keyword arguments that are also passed to assertRaises()
.
class TestComputedAttrs(unittest.TestCase):
def setUp(self) -> None:
self._sut = ParrotComputedAttributes()
def test_read_missing_property(self):
with self.assertRaises(AttributeError):
self._sut.missing_property
Running⌗
A common way is to trigger unittest.main()
like so:
if __name__ == "__main__":
unittest.main()
Alternatively it provides a first-class CLI, that supports simple module, class or individual test methods:
python3 -m unittest objects.test.test_parrot.MyTestCase.test_default_voltage
Test modules can also be specified by path:
python3 -m unittest objects/test/test_parrot.py
Pro tips⌗
- If you shuffle tests into a
test
directory in the source tree, you’ll need to make sure the code under test is available on thePYTHONPATH
pytest⌗
Pytest is the defacto standard.
TODO⌗
unittest
- monkey patching
pytest
- mocking