To do that you can mock the class function with the @patch like that

from mock import patch

# Our class to test
class FooObject():
    def update(self, obj):
        print obj

# Mock the update method
@patch.object(FooObject, 'update')
def test(mock1):
    # test that the update method is actually mocked
    assert FooObject.update is mock1
    foo = FooObject()
    foo.update('foo')
    return mock1

# Test if the mocked update method was called with 'foo' parameter
mock1 = test()
mock1.assert_called_once_with('foo')

You can even mock more functions like that:

from mock import patch

class FooObject():
    def update(self, obj):
        print obj

    def restore(self, obj):
        print obj

@patch.object(FooObject, 'restore')
@patch.object(FooObject, 'update')
def test(mock1, mock2):
    assert FooObject.update is mock1
    assert FooObject.restore is mock2
    foo = FooObject()
    foo.update('foo')
    foo.restore('bar')
    return mock1, mock2

mock1, mock2 = test()
mock1.assert_called_once_with('foo')
mock2.assert_called_once_with('bar')
Answer from Tim Rijavec 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
🌐
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.
🌐
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.
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.

🌐
GitHub
github.com › python › cpython › issues › 122726
Mocked value at method level not overriding class-level mock in unittest · Issue #122726 · python/cpython
August 6, 2024 - Create a test class with a class-level mock using @mock.patch. Add a method-level mock to one of the test methods to override the class-level mock.
🌐
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 - This is the default behaviour, but it can be overridden in different ways. For example you can assign a value to an attribute in the Mock by: Assign it directly, like you’d do with any Python object. Use the configure_mock method on an instance.
Top answer
1 of 1
44

Well, turns out that a good night sleep and a cold shower made me rethink the whole issue. I'm still very new to the concept of mocking, so it still hasn't sunk in quite right.

The thing is, there's no need to override the patch to a mocked object. It's a mocked object and that means I can make it do anything. So my first try was:

@mock.patch('method_to_patch', mock.Mock(return_value=1))
class Tests(TestCase):

    def test_override(self):
         method_to_patch.return_value = 2
         (....)

That worked, but had the side effect of changing the return value for all following tests. So then I tried:

@mock.patch('method_to_patch', mock.Mock(return_value=1))
class Tests(TestCase):

    def test_override(self):
         method_to_patch.return_value = 2
         (....)
         method_to_patch.return_value = 1

And it worked like a charm. But seemed like too much code. So then I went the down the road of context management, like this:

@mock.patch('method_to_patch', mock.Mock(return_value=1))
class Tests(TestCase):

    def test_override(self):
         with mock.patch('method_to_patch', mock.Mock(return_value=2):
             (....)

I think it seems clearer and more concise.

About the order in which the patch decorators were being applied, it's actually the correct order. Just like stacked decorators are applied from the bottom up, a method decorator is supposed to be called before the class decorator. I guess it makes sense, I was just expecting the opposite behavior.

Anyway, I hope this help some poor newbie soul like mine in the future.

Find elsewhere
🌐
GitHub
github.com › fastapi › fastapi › discussions › 7920
How do I mock or override classes and methods for unittests? · fastapi/fastapi · Discussion #7920
I managed to get my tests running again by installing the great package pytest-mock. I also realized the reason for my mock failing was a case of what gets initialized when so I made it lazy and that fixed things.
Author: fastapi
🌐
Ets-labs
python-dependency-injector.ets-labs.org › providers › overriding.html
Provider overriding — Dependency Injector 4.48.3 documentation
This method receives a single argument called overriding. If the overriding value is a provider, this provider is called instead of the original. If value is not a provider, this value is returned instead of calling the original provider. import dataclasses import unittest.mock from ...
🌐
Readthedocs
testfixtures.readthedocs.io › en › latest › mocking.html
Mocking out objects and methods - testfixtures 11.0.0 documentation
It may also mean replacing chunks of complex functionality that aren’t the subject of the test with mock objects that allow you to check that the mocked out functionality is being used as expected. Python has a standard mock implementation in the form of unittest.mock which is also available ...
🌐
Python
docs.python.org › 3 › library › unittest.mock.html
unittest.mock — mock object library
The Mock classes have support for mocking magic methods. See magic methods for the full details. The mock classes and the patch() decorators all take arbitrary keyword arguments for configuration. For the patch() decorators the keywords are passed to the constructor of the mock being created.
🌐
pytest
docs.pytest.org › en › 7.1.x › how-to › monkeypatch.html
How to monkeypatch/mock modules and environments — pytest documentation
The mock of r needs a .json() method which returns a dictionary. This can be done in our test file by defining a class to represent r. # 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.
Top answer
1 of 1
1

Apart from the multiple errors in the example code I wrote up off the top of my head at the cafe ...

The problem was (mostly) that I was using return_value instead of side_effect to 'replace' the patched class with my own subclass.

My need, re-stated perhaps more clearly now, is to override a single method, set_some_stuff, in a class within the unit under test (UUT) but without mocking the class.

The method issues several 'self.foo = bar' statements, which I want to change for testing purposes. Thus, mocking the method's (unused) return value is not enough ... and patch.object seems to lose class context, "'self' unknown" or the like.

Finally, here is the working code, doing what I need ...

import unittest
import mock

class SetupClass(object):
    def set_some_stuff(self):
        data_list = ['data not available', 'on test_platform'] # CRASH!
        self.something = data_list[0]
        self.something_else = data_list[1]

class UUT:
    def __init__(self):
        self.config = SetupClass()
        self.config.set_some_stuff()
        assert self.config.something == 'foo' # <-- used to crash before here ...
        self.got_here = True # ... but now the override method from
                             # WedgeClass is being used! :=)

"""
Subclass the original class, overriding just the method in question.  Then set
the subclass as the side_effect of the patched original, effectively replacing it.
"""
class WedgeClass(SetupClass):
    def set_some_stuff(self):
        self.something = 'foo'
        pass # I'm a Python newbie, in too deep

class UnitTests(unittest.TestCase):

    @mock.patch(__module__+'.SetupClass')
    def test_UUT(self, mock1):
        wedge_class = WedgeClass()
        mock1.side_effect = WedgeClass # <--- Ureka! 'side_effect' not 'return_value' was the ley!

        uut = UUT()
        self.assertTrue(uut.got_here)
🌐
Hakin9
hakin9.org › what-the-mock - a-cheatsheet-for-mocking-in-python-by-yeray-diaz
404 - Hakin9 - IT Security Magazine
January 17, 2020 - eBooks · Courses · Subscription · Corporate · Education · About Us · Contact Us · No products in the cart · LOGIN / SIGN UP · Our brands
🌐
FreBlogg
freblogg.com › pytest-functions-mocking-1
Mocking functions in Python with Pytest Part I · FreBlogg
April 11, 2020 - A mock replaces a function with a dummy you can program to do whatever you choose. This is also called ‘Patching’. For the rest of this series, I am going to use ‘mock’ and ‘patch’ interchangeably. Unlike the majority of programming languages, Python comes with a built-in library ...