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.

  1. First we import datetime and Mock:

[1]:
from datetime import datetime
from unittest.mock import Mock
  1. Then we define two test days:

[2]:
monday = datetime(year=2021, month=10, day=11)
saturday = datetime(year=2021, month=10, day=16)
  1. Now we define a method to check the working days, where Python’s datetime library treats Mondays as 0 and Sundays as 6:

[3]:
def is_workingday():
    today = datetime.today()
    return (0 <= today.weekday() < 5)
  1. Then we mock datetime:

[4]:
datetime = Mock()
  1. 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)
Cell In[7], line 2
      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()

See also:

You can use responses to create mock objects for the Requests library.