Derte Trdelnik
Derte Trdelnik

Reputation: 2706

Mocking class by replacing it

imagine you have a module

from module.my_module import Foo


def my_function():
    foo = Foo()
    return whatewer_can_happen(foo)

that you want to test like this

class TestFoo:
    def __init__():
         pass
    
    def dont_care():
        return 9


def test_something():
    with mock.patch('tested_module.Foo') as mocked_class:
        mocked_class.side_effect = lambda *args: TestFoo(*args)
        assert tested_module.my_function() == 'not important'

essentially as if you wanted to inject the TestFoo in place of Foo (example wont work ofc, only for illustration)

How to mock the Foo class in the tested module without changing the tested code? If it is not possible, why - how are classes in python so different to functions that mocking them is not possible?

I am not looking for ways to do it differently(factory function/mocking only class functions directly etc)

It would in some cases just be helpful (and more readable) to be able to write mock classes and inject them for use into the tested module

Upvotes: 1

Views: 6551

Answers (1)

MrBean Bremen
MrBean Bremen

Reputation: 16815

You can always provide your own mock instead of the default MagicMock instance by passing it to the mock.patch call:

def test_something():
    with mock.patch('tested_module.Foo', TestFoo):
        assert tested_module.my_function() == 'not important'

Note that you can't use side_effect here, because your new object is not a Mock object. Also, if you use the decorator version, there will be no extra argument for the mock:

@mock.patch('tested_module.Foo', TestFoo):
def test_something():
    assert tested_module.my_function() == 'not important'

Here is the relevant part of the documentation:

If new is omitted, then the target is replaced with an AsyncMock if the patched object is an async function or a MagicMock otherwise. If patch() is used as a decorator and new is omitted, the created mock is passed in as an extra argument to the decorated function. If patch() is used as a context manager the created mock is returned by the context manager.

Upvotes: 2

Related Questions