in Python 3.6, I use unittest.mock.patch
to patch a function like this:
class SampleTest(TestCase):
@mock.patch('some_module.f')
def test_f(self, mocked_f):
f()
mocked_f.assert_called()
This passes a mock.MagicMock()
as mocked_f
and everything works fine. However, when I want to use a custom mock object instead of the default mock.MagicMock()
using new
argument, the patch decorator does not pass the mocked object to the test_f
method. Running this code will raise a TypeError
:
class SampleTest(TestCase):
@mock.patch('some_module.f', new=lambda: 8)
def test_f(self, mocked_f):
f()
mocked_f.assert_called()
TypeError: test_f() missing 1 required positional argument: 'mocked_f'
My question is: why is this happening?
patch() unittest. mock provides a powerful mechanism for mocking objects, called patch() , which looks up an object in a given module and replaces that object with a Mock . Usually, you use patch() as a decorator or a context manager to provide a scope in which you will mock the target object.
New in version 3.3. unittest.mock is a library for testing in Python. It allows you to replace parts of your system under test with mock objects and make assertions about how they have been used. unittest.mock provides a core Mock class removing the need to create a host of stubs throughout your test suite.
Mock vs. So what is the difference between them? MagicMock is a subclass of Mock . It contains all magic methods pre-created and ready to use (e.g. __str__ , __len__ , etc.). Therefore, you should use MagicMock when you need magic methods, and Mock if you don't need them.
I think it's probably correct that the reason the mocked object is not passed to the decorated function when new
is specified, is that you will normally already have a reference to the that object, and so don't need it passed into the decorated function.
Notice however that if you use new_callable
instead of new
then the mocked object is passed to the decorated function. This makes sense since you normally won't have a reference to the object returned from the callable.
so you can do something like the following:
def my_custom_mock_factory():
my_mock = mock.Mock()
# customisations to my_mock
return my_mock
class SampleTest(TestCase):
@mock.patch('some_module.f', new_callable=my_custom_mock_factory)
def test_f(self, mocked_f):
f()
mocked_f.assert_called()
From the documentation (emphasis mine):
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.
With new
being used explicitly, the decorator does not pass the mocked object as a parameter (presumably because it expects you to already have a reference that you could use without needing an argument).
In this case, a workaround would be to configure the mock after it has been passed to your test:
class SampleTest(TestCase):
@mock.patch('tests.f')
def test_f(self, mocked_f):
mocked_f.return_value = 8
# or
# mocked_f.side_effect = lambda: 8
f()
mocked_f.assert_called()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With