Skip to content

Testing mock and monkeypatch

Mocking

A mock object replaces and imitates a real object during the test. It is a flexible and powerful tool for improving your test quality.

MagicMock

The unittest.mock is the library for mocking in Python. It provides an easy way to introduce mocks into your tests. For example, the main.py file:

import time


def delay(seconds: int, func):
    time.sleep(seconds)
    return func()

The test_main.py file:

from unittest import mock

from main import delay


def test_function_has_called():
    mock_function = mock.MagicMock()
    delay(3, mock_function)
    mock_function.assert_called_once()

Mocking With an Unittest mock.patch

The unittest.mock provides a powerful tool for mocking objects — patch(), which looks up an object in a given module and replaces that object with a mock.

Usually, we use the patch() as a decorator or a context manager to provide a scope in which you can mock the target object.

If you want to mock an object for the duration of your entire test function, you can use the patch() as a function decorator.

An example of using the patch():

# test_main.py
from unittest import mock

from main import delay


@mock.patch("time.sleep")
def test_function_has_called(mocked_sleep):
    delay(100, lambda: None)
    mocked_sleep.assert_called_once_with(100)

Mocking With a Context Manager

Sometimes, you’ll need to use the patch() as a context manager rather than a decorator, for example, when:

you only want to mock an object for a part of the test scope; you are already using too many decorators or parameters, which hurt your test’s readability.

For example:

from unittest import mock

from main import delay


def test_function_has_called():
    with mock.patch("time.sleep") as mocked_sleep:
        delay(100, lambda: None)
        mocked_sleep.assert_called_once_with(100)

Pytest Monkeypatch

The pytest also provided the mocking mechanism —  monkeypatch, which is analog for unittest.mock. For example, the main.py file:

import os


def get_current_path():
    current_path = os.getcwd()
    return current_path  # Return the current directory

The test_main.py file:

import os

from main import get_current_path


def test_get_current_directory(monkeypatch):

    def mock_getcwd():
        return '/data/user/directory123'

    monkeypatch.setattr(os, 'getcwd', mock_getcwd)  # Mocking the result of os.getcwd()
    assert get_current_path() == '/data/user/directory123'