In the end I used Python's mock, which allows me to override complicated_function without having to adjust the original code in any way.

Here is the original script, and note that complicated_function is not passed in to my_loopy_function as an 'action_function' parameter (which was what I tried in my earlier solutions):

// my_script.py

def my_loopy_function():
    aggregate_value = 0
    for x in range(10):
        aggregate_value = aggregate_value + complicated_function(x)
    return aggregate_value

def complicated_function(x):
    a = do()
    b = something()
    c = complicated()
    return a + b + c

and here is the script I am using to test it:

// test_my_script.py

import unittest
import mock
from my_script import my_loopy_function

class TestMyModule(unittest.TestCase):
    @mock.patch('my_script.complicated_function')
    def test_1(self, mocked):
        mocked.return_value = 1
        self.assertEqual(10, my_loopy_function())

This works just as I had wanted:

  1. I am able to substitute functions with a simpler version of themselves that I can more easily test,
  2. I do not need to alter my original code in any way (such as I was trying -- which was effectively by passing in function pointers), the mock module gives me post-coding access to the innards.

Thanks to austin for his suggestion to use mock. BTW I am using Python 2.7 and therefore used the pip-installable mock from PyPI.

Answer from Robert on Stack Overflow
Top answer
1 of 4
8

In the end I used Python's mock, which allows me to override complicated_function without having to adjust the original code in any way.

Here is the original script, and note that complicated_function is not passed in to my_loopy_function as an 'action_function' parameter (which was what I tried in my earlier solutions):

// my_script.py

def my_loopy_function():
    aggregate_value = 0
    for x in range(10):
        aggregate_value = aggregate_value + complicated_function(x)
    return aggregate_value

def complicated_function(x):
    a = do()
    b = something()
    c = complicated()
    return a + b + c

and here is the script I am using to test it:

// test_my_script.py

import unittest
import mock
from my_script import my_loopy_function

class TestMyModule(unittest.TestCase):
    @mock.patch('my_script.complicated_function')
    def test_1(self, mocked):
        mocked.return_value = 1
        self.assertEqual(10, my_loopy_function())

This works just as I had wanted:

  1. I am able to substitute functions with a simpler version of themselves that I can more easily test,
  2. I do not need to alter my original code in any way (such as I was trying -- which was effectively by passing in function pointers), the mock module gives me post-coding access to the innards.

Thanks to austin for his suggestion to use mock. BTW I am using Python 2.7 and therefore used the pip-installable mock from PyPI.

2 of 4
3

Don't try to override complicated_function with action_function, just use complicated_function as the default action_function:

def my_loopy_function(action_function=complicated_function):
    aggregate_value = 0
    for x in range(10):
        aggregate_value = aggregate_value + action_function(x)
    return aggregate_value
🌐
pytest
docs.pytest.org › en › stable › how-to › monkeypatch.html
How to monkeypatch/mock modules and environments - pytest documentation
# contents of test_app.py, a simple test for our API retrieval # import requests for the purposes of monkeypatching import requests # our app.py that includes the get_json() function # this is the previous code block example import app # custom class to be the mock return value # will override the requests.Response returned from requests.get class MockResponse: # mock json() method always returns a specific testing dictionary @staticmethod def json(): return {"mock_key": "mock_response"} def test_get_json(monkeypatch): # Any arguments may be passed and mock_get() will always return our # mocked object, which only has the .json() method.
Discussions

python - How to override a mock for an individual test within a class that already has a mock - Stack Overflow
I have a test class that has a mock decorator, and several tests. Each test receives the mock, because mock is defined on the class level. Great. Here's what it looks like: @mock.patch("foo&qu... More on stackoverflow.com
🌐 stackoverflow.com
mocking - Python: using Mock to override class method - Stack Overflow
I would like to override update method for the unittest using Python's Mock tool. How would I do it? More on stackoverflow.com
🌐 stackoverflow.com
python - How can I mock external function that is used in class method? - Stack Overflow
I want to mock a function that is used in some method. This function is located in other module. How can I do that? Tried this option, but it does not work. from pack import utils from pack. More on stackoverflow.com
🌐 stackoverflow.com
The function is not overwritten when using monkeypatch or mocker (pytest-mock)
My guess is that this is because when you import a function at the beginning of a module, it is saved in that module. And when mockers start overwriting the path to the function, they do not touch the already imported objects. More on github.com
🌐 github.com
2
August 31, 2024
🌐
Python
docs.python.org › 3 › library › unittest.mock-examples.html
unittest.mock — getting started
Mock (in all its flavours) uses a method called _get_child_mock to create these “sub-mocks” for attributes and return values. You can prevent your subclass being used for attributes by overriding this method.
🌐
OneUptime
oneuptime.com › home › blog › how to use pytest with mocking
How to Use pytest with Mocking
February 2, 2026 - The mocker fixture provided by pytest-mock simplifies mocking in tests. It automatically handles cleanup after each test. Use mocker.patch() to replace a function with a mock during a test.
🌐
pytest
docs.pytest.org › en › 7.1.x › how-to › monkeypatch.html
How to monkeypatch/mock modules and environments — pytest documentation
# contents of test_app.py, a simple test for our API retrieval # import requests for the purposes of monkeypatching import requests # our app.py that includes the get_json() function # this is the previous code block example import app # custom class to be the mock return value # will override the requests.Response returned from requests.get class MockResponse: # mock json() method always returns a specific testing dictionary @staticmethod def json(): return {"mock_key": "mock_response"} def test_get_json(monkeypatch): # Any arguments may be passed and mock_get() will always return our # mocked object, which only has the .json() method.
🌐
Skybert
skybert.net › python › mocking-classes-and-overriding-methods-in-python
Mocking classes and overriding methods in Python | skybert.net
November 7, 2018 - import types import unittest.mock class ExploringMocking(unittest.TestCase): def test_mocking_a_class(self): waterfall = unittest.mock.create_autospec(Waterfall) waterfall.height_in_feet = types.MethodType( self.my_height_func, self ) assert waterfall.height_in_feet() == 10 def my_height_func(self, ref): return 10 · The essential bit here is the types.MethodType which is what you need to do when overriding the method on a class instance.
🌐
FreBlogg
freblogg.com › pytest-functions-mocking-1
Mocking functions in Python with Pytest Part I · FreBlogg
April 11, 2020 - Unless you need magic methods like the above implemented, you can stick to Mock. Pytest-mock gives you access to both of these classes with an easy to use interface. patch is another function that comes from the 'unittest' module that helps replace functions with mocks.
Top answer
1 of 2
3

Yes! You can leverage the setUp/tearDown methods of the unittest.TestCase and the fact that unittest.mock.patch in its "pure" form (i.e. not as context manager or decorator) returns a "patcher" object that has start/stop methods to control when exactly it should do its magic.

You can call on the patcher to start inside setUp and to stop inside tearDown and if you keep a reference to it in an attribute of your test case, you can easily stop it manually in selected test methods. Here is a full working example:

from unittest import TestCase
from unittest.mock import patch


class Foo:
    @staticmethod
    def bar() -> int:
        return 1


class TestMyThing(TestCase):
    def setUp(self) -> None:
        self.foo_bar_patcher = patch.object(Foo, "bar", return_value=42)
        self.mock_foo_bar = self.foo_bar_patcher.start()
        super().setUp()

    def tearDown(self) -> None:
        self.foo_bar_patcher.stop()
        super().tearDown()

    def test_a(self):
        self.assertEqual(42, Foo.bar())

    def test_b(self):
        self.assertEqual(42, Foo.bar())

    def test_c(self):
        self.assertEqual(42, Foo.bar())

    def test_d(self):
        self.foo_bar_patcher.stop()
        self.assertEqual(1, Foo.bar())

This patching behavior is the same, regardless of the different variations like patch.object (which I used here), patch.multiple etc.

Note that for this example it is not necessary to keep a reference to the actual MagicMock instance generated by the patcher in an attribute, like I did with mock_foo_bar. I just usually do that because I often want to check something against the mock instance in my test methods.

It is worth mentioning that you can also use setUpClass/tearDownClass for this, but then you need to be careful with re-starting the patch, if you stop it because those methods are (as the name implies) only called once for each test case, whereas setUp/tearDown are called once before/after each test method.

PS: The default implementations of setUp/tearDown on TestCase do nothing, but it is still good practice IMO to make a habit of calling the superclass' method, unless you deliberately want to omit that call.

2 of 2
1

While accepted answer is perfectly fine, I'd go for approach which keeps decorator for the class and uses context managers for methods in which you want to override a mock, see sample code below:

@mock.patch("foo", bar)
class TestMyThing(TestCase):
  def test_A(self):
    assert something

  def test_B(self):
    assert something

  def test_C(self):
    assert something

  def test_D(self):
    with patch('foo', baz):
        assert something

This achieves your goal, as context manager mock is applied inside of a test function, so it happens after applying the class decorator mock and therefore it effectively overrides class decorator mock. Also, I think it's simpler and it requires less code, especially if you have no other reason to implement setUp() and tearDown() methods.

Find elsewhere
🌐
pytest
docs.pytest.org › en › 6.2.x › monkeypatch.html
Monkeypatching/mocking modules and environments — pytest documentation
February 11, 2022 - # contents of test_app.py, a simple test for our API retrieval # import requests for the purposes of monkeypatching import requests # our app.py that includes the get_json() function # this is the previous code block example import app # custom class to be the mock return value # will override the requests.Response returned from requests.get class MockResponse: # mock json() method always returns a specific testing dictionary @staticmethod def json(): return {"mock_key": "mock_response"} def test_get_json(monkeypatch): # Any arguments may be passed and mock_get() will always return our # mocked object, which only has the .json() method.
🌐
Medium
yeraydiazdiaz.medium.com › what-the-mock-cheatsheet-mocking-in-python-6a71db997832
What the mock? — A cheatsheet for mocking in Python | by Yeray Diaz | Medium
August 19, 2019 - Or pass keyword arguments to the Mock class on creation. To override calls to the mock you’ll need to configure its return_value property, also available as a keyword argument in the Mock initializer.
🌐
GitHub
github.com › fastapi › fastapi › discussions › 7920
How do I mock or override classes and methods for unittests? · fastapi/fastapi · Discussion #7920
To be clear I'm using Python's unittest and built in mock library. I'm trying to get back canned data from a call to a view via the TestClient. ... There was an error while loading. Please reload this page. Something went wrong. There was an error while loading. Please reload this page. ... This is a very guide using pytest: https://testdriven.io/blog/fastapi-crud/. Here pytest monkeypatch is used to mock behavior.
Author: fastapi
Top answer
1 of 1
3

You can use unittest.mock.patch or the pytest-mock plugin with the mocker fixture.

Your package

pack/another_pack.py:

from pack import utils

class SomeClass:
    def foo(self):
        return utils.my_function()

pack/utils.py:

def my_function():
    return 'original'

Tests

import pytest
from unittest.mock import patch
from pack.another_pack import SomeClass


# Replace my_function with another function. You could pass parameters
# to the mocked function and handle them in the replacement.
@pytest.mark.parametrize("attr", ["a", "b", "c"])
def test_replace(attr):
    def mock_return():
        return attr

    with patch("pack.another_pack.utils.my_function", new=mock_return):
        assert SomeClass().foo() == attr


# If you just want to override the return value.
@pytest.mark.parametrize("attr", ["a", "b", "c"])
def test_return_value(attr):
    with patch("pack.another_pack.utils.my_function") as my_func:
        my_func.return_value = attr
        assert SomeClass().foo() == attr


# With the pytest-mock plugin and the mocker fixture instead of unittest.mock.
@pytest.mark.parametrize("attr", ["a", "b", "c"])
def test_mock_plugin(attr, mocker):
    my_func = mocker.patch("pack.another_pack.utils.my_function")
    my_func.return_value = attr
    assert SomeClass().foo() == attr

Note that in all tests the first argument of patch is the name of the module where you want to mock the function (pack.another_pack) with the name of the function how it appears in the module (utils.my_function).

my_function is mocked for the entire pack.another_pack module.

🌐
GitHub
github.com › pytest-dev › pytest › issues › 12757
The function is not overwritten when using monkeypatch or mocker (pytest-mock) · Issue #12757 · pytest-dev/pytest
August 31, 2024 - When you use a mock function from a module, it does not overwrite it main.py def func(): return 'in function' test_bug.py from main import func def test_bug(monkeypatch): def mock_func(*a, **k): return 'in mock' monkeypatch.setattr('main...
Author: pytest-dev
🌐
Stack Overflow
stackoverflow.com › questions › 70838892 › overriding-mocking-a-hardcoded-value-in-python-unittest-pytest
unit testing - Overriding/mocking a hardcoded value in python unittest/pytest - Stack Overflow
January 24, 2022 - how can I mock/override the path ... bronze badges 4 · The best you can do is patch upload with a function that calls the real upload function with your own argument....
🌐
Readthedocs
pytest-mock.readthedocs.io › en › latest › usage.html
Usage - pytest-mock documentation
Besides functions and normal methods, mocker.spy also works for class and static methods.
🌐
Stack Overflow
stackoverflow.com › questions › 65997212 › pytest-override-function-thats-not-in-a-class
python 3.x - pytest override function thats not in a class - Stack Overflow
I want to be able to test this function, and override one of the functions that it calls because I don't want it to actually go out and make a call, I want to provide a return_value for that function. So far I've seen this is mainly doable if you're using a class, but this is an API endpoint and I'm not using a class in this case. Here is the actual endpoint (simplified): def _get_mock_request(self, queryStringParameters): return { "headers": {"x-api-key": "SOME-KEY"}, "requestContext": { "resourceId": "t89kib", "authorizer": { "x-authorizer-key": "SOME KEY", "principalId": "9de3f415a97e410386
🌐
Python
docs.python.org › 3 › library › unittest.mock.html
unittest.mock — mock object library
Create the child mocks for attributes and return value. By default child mocks will be the same type as the parent. Subclasses of Mock may want to override this to customize the way child mocks are made.
🌐
DEV Community
dev.to › mohamedabdelwahab › mastering-pytest-monkeypatch-simplify-your-testing-jj8
Mastering Pytest Monkeypatch: Simplify Your Testing - DEV Community
December 23, 2024 - The monkeypatch fixture in pytest allows you to modify or replace: ... This dynamic modification is temporary and only applies to the scope of the test, ensuring the original behavior is restored once the test ends. This makes monkeypatch particularly useful for mocking, overriding dependencies, or testing code under specific conditions without making permanent changes.
🌐
Towards Data Science
towardsdatascience.com › home › latest › pytest with marking, mocking, and fixtures in 10 minutes
Pytest with Marking, Mocking, and Fixtures in 10 Minutes | Towards Data Science
July 31, 2022 - Note that you cannot mock the desired function you are testing but can mock any dependencies, or even nested dependencies, the desired function relies on. As discussed in previous sections, the configuration file pytest.ini can be defined at the base directory to bypass ModuleNotFoundError and to define unit test groups.