Backend Development 9 min read

Using pytest-mock to Mock Functions and Objects in Python Tests

This article introduces the pytest-mock plugin, explains when and how to use it for mocking functions, classes, and external services in Python tests, and provides a range of basic to advanced code examples along with important considerations and best‑practice tips.

Test Development Learning Exchange
Test Development Learning Exchange
Test Development Learning Exchange
Using pytest-mock to Mock Functions and Objects in Python Tests

pytest-mock is a powerful pytest plugin that simplifies creating mock objects for functions, classes, and methods, making it especially useful for API automation testing where external dependencies need to be simulated.

Use case : When an interface test depends on an external service, pytest-mock can mock that service so the test runs independently.

Example code

# app.py
import requests

def get_data_from_service():
    response = requests.get('https://example.com/api/data')
    return response.json()

def process_data(data):
    # Ensure data['value'] is greater than 10
    if data['value'] > 10:
        return True
    return False

Test code

# test_app.py
import pytest
from app import process_data

def test_process_data(mocker):
    # Mock the get_data_from_service function's return value
    mocker.patch('app.get_data_from_service', return_value={'value': 20})
    # Test process_data function
    assert process_data(get_data_from_service()) is True

Key considerations

Namespace : Ensure the patch path matches the actual module where the target is defined.

Scope : Mocks are scoped to the test function by default; use mocker.patch.object or specify scope for finer control.

Cleanup : pytest-mock automatically cleans up mocks after each test.

Side effects : Verify that mocked functions do not introduce unintended side effects.

Mock attributes : Use mocker.Mock or mocker.NonCallableMock to create objects with specific attributes.

Running the test

$ pytest test_app.py
============================= test session starts ==============================
platform linux -- Python 3.10.6, pytest-7.2.0, pluggy-1.0.0
rootdir: /path/to/project
collected 1 item

test_app.py .                                                         [100%]
============================== 1 passed in 0.01s ==============================

Advanced examples

1. Mocking classes and objects

import pytest
from app import MyClass

class TestMyClass:
    def test_method(self, mocker):
        # Create a mock class instance
        mock_instance = mocker.Mock()
        mock_instance.method.return_value = "mocked_value"
        # Patch MyClass to return the mock instance
        mocker.patch('app.MyClass', return_value=mock_instance)
        my_instance = MyClass()
        result = my_instance.method()
        assert result == "mocked_value"

2. Mocking modules and packages

import pytest
from app import module

class TestModule:
    def test_module_functions(self, mocker):
        mocked_module = {
            'func1': mocker.Mock(return_value="mocked_func1"),
            'func2': mocker.Mock(return_value="mocked_func2")
        }
        mocker.patch.dict('app.module.__dict__', mocked_module)
        assert module.func1() == "mocked_func1"
        assert module.func2() == "mocked_func2"

3. Mocking external libraries or third‑party services

import pytest
import requests
from app import get_data_from_service

class TestGetData:
    def test_get_data(self, mocker):
        mocker.patch('requests.get', return_value=mocker.Mock(json=lambda: {"value": 20}))
        data = get_data_from_service()
        assert data["value"] == 20

4. Mocking asynchronous functions

import pytest
import asyncio
from app import async_get_data_from_service

class TestAsyncGetData:
    async def test_async_get_data(self, mocker):
        mock_response = mocker.AsyncMock()
        mock_response.json.return_value = {"value": 20}
        mocker.patch('app.async_get_data_from_service', new=mock_response)
        data = await async_get_data_from_service()
        assert data["value"] == 20

5. Mocking exception raising

import pytest
from app import get_data_from_service

class TestGetData:
    def test_get_data_exception(self, mocker):
        mocker.patch('requests.get', side_effect=requests.exceptions.RequestException)
        with pytest.raises(requests.exceptions.RequestException):
            get_data_from_service()

6. Mocking multiple return values

import pytest
from app import get_data_from_service

class TestGetData:
    def test_get_data_multiple_values(self, mocker):
        mocker.patch('requests.get', side_effect=[{'value': 20}, {'value': 30}])
        data1 = get_data_from_service()
        data2 = get_data_from_service()
        assert data1["value"] == 20
        assert data2["value"] == 30

7. Mocking properties

import pytest
from app import MyClass

class TestMyClass:
    def test_property(self, mocker):
        mock_property = mocker.PropertyMock(return_value="mocked_value")
        mocker.patch('app.MyClass.property', new_callable=mock_property)
        my_instance = MyClass()
        assert my_instance.property == "mocked_value"

8. Mocking authentication mechanisms of external services

import pytest
from app import authenticate_and_get_data

class TestAuthentication:
    def test_authenticate_and_get_data(self, mocker):
        mocker.patch('app.authenticate', return_value=True)
        data = authenticate_and_get_data()
        assert data["value"] == 20

Additional notes

Ensure the mock path is correct for the target function.

Maintain proper test scope to avoid affecting other tests.

pytest-mock automatically restores mocks after each test, but manual mocks should be reset with mocker.resetall() or mocker.restore() if needed.

Document mock usage clearly to aid future maintenance.

Mockpytestpytest-mock
Test Development Learning Exchange
Written by

Test Development Learning Exchange

Test Development Learning Exchange

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.