More unit testing in Python. Covers more advanced concepts not discussed in part 1.
Assertions on more complex data
A common scenario is to perform assertions on more complex data. Consider the following method and its associated test:
# project/myclass.py
def shuffle(self, my_list):
random.shuffle(my_list)
return my_list
# tests/test_myclass.py
def test_list(self):
expected = [1, 2, 3, 4]
actual = self._myclass.shuffle(expected[:])
self.assertCountEqual(expected, actual)
assertCountEqual
is used in place of assertEqual
in order to ensure that the elements in the list remain the same. However, assertCountEqual
has its limitations and will not work on much more complicated objects. If there was a need to test the equality of a dictionary of lists, a custom function has to be written in order to ensure equality.
Handling multiple calls
Some methods need to make multiple external calls to the same service. A simple example is provided below:
# project/myclass.py
def multi_add(self, a, b, c):
ab = self._addHelper.add(a, b)
abc = self._addHelper.add(ab, c)
return abc
# tests/test_myclass.py
def test_multicalls(self):
# GIVEN
calls = [
call(2, 3),
call(5, 7)
]
def side_effect(*args):
if args[0] == 2:
return 5
return 12
self._addhelpermock.add = MagicMock(side_effect=side_effect)
# WHEN
actual = self._myclass.multi_add(2, 3, 7)
# THEN
self._addhelpermock.add.assert_has_calls(calls)
self.assertEqual(12, actual)
Exceptions
When testing with exceptions (e.g. bad response from server, wrongly formatted input etc.), a context manager is used when asserting the exception is raised. The context captured by the context manager can then be examined to make assertions upon the exception.
# project/myclass.py
class MyException(Exception):
def __init__(self, message):
super(MyException, self).__init__(message)
self.message = message
def create_exception(self):
my_dict = {}
try:
my_dict['key'] += 4
except KeyError:
raise MyException('Invalid key')
# tests/test_myclass.py
def test_exception(self):
with self.assertRaises(MyException) as cm:
self._myclass.create_exception()
self.assertEqual('Invalid key', cm.exception.message)