Mock#
Mock objects promote tests based on the behaviour of objects. The Python library mock allows you to replace parts of the system under test with mock objects and make statements about their use.
Installation#
mock is included in the Python standard library since Python 3.3. For older versions of Python you can install it with:
$ bin/python -m pip install mock
Example#
In our example, we want to check whether the working days from Monday to Friday are determined correctly.
First we import
datetime
andMock
:
[1]:
from datetime import datetime
from unittest.mock import Mock
Then we define two test days:
[2]:
monday = datetime(year=2021, month=10, day=11)
saturday = datetime(year=2021, month=10, day=16)
Now we define a method to check the working days, where Python’s datetime library treats Mondays as
0
and Sundays as6
:
[3]:
def is_workingday():
today = datetime.today()
return (0 <= today.weekday() < 5)
Then we mock
datetime
:
[4]:
datetime = Mock()
Finally, we test our two mock objects:
[5]:
datetime.today.return_value = monday
assert is_workingday()
[6]:
datetime.today.return_value = saturday
assert not is_workingday()
[7]:
datetime.today.return_value = monday
assert not is_workingday()
---------------------------------------------------------------------------
AssertionError Traceback (most recent call last)
/var/folders/f8/0034db6d78s5r6m34fxhpk7m0000gp/T/ipykernel_76847/2926786502.py in <module>
1 datetime.today.return_value = monday
----> 2 assert not is_workingday()
AssertionError:
mock.ANY
#
With mock.ANY you can check whether a value is present at all without having to check an exact value:
[8]:
from unittest.mock import ANY
mock = Mock(return_value=None)
mock('foo', bar=object())
mock.assert_called_once_with('foo', bar=ANY)
See also:
In test_report.py of the OpenStack container service Zun you will find more practical examples for ANY
.
patch
decorator#
To create mock classes or objects, the patch
decorator can be used. In the following examples, the output of os.listdir
is mocked. For this, the file example.txt
does not have to be present in the directory:
[9]:
import os
from unittest import mock
[10]:
@mock.patch("os.listdir", mock.MagicMock(return_value="example.txt"))
def test_listdir():
assert "example.txt" == os.listdir()
test_listdir()
Alternatively, the return value can also be defined separately:
[11]:
@mock.patch("os.listdir")
def test_listdir(mock_listdir):
mock_listdir.return_value = "example.txt"
assert "example.txt" == os.listdir()
test_listdir()