9
  1. What is the difference between using mock.Mock() vs mock.patch()?

  2. When to use mock.Mock() and when to use mock.patch()

  3. I've read that Mock is used to replace something that is used in the current scope, vs, patch is used to replace something that is imported and/or created in another scope. Can someone explain what that means?

  • If we are testing in a separate test file, wouldn't every classmethod, staticmethod, intancemethod being tested imported from the dev/production files? Does that mean only patch should be used here? And if I were to test on the same file as the code being tested, mock is preferred to be used? Is that correct?
nbro
  • 15,395
  • 32
  • 113
  • 196
0x5929
  • 400
  • 1
  • 4
  • 16
  • Your question is not clear - `mock.Mock` is a class, and `mock.patch` is a method to replace an object with an instance of that class, so the two are not really comparable. Please check [the documentation](https://docs.python.org/3/library/unittest.mock.html?highlight=mock#module-unittest.mock). – MrBean Bremen Aug 06 '20 at 06:09
  • @MrBeanBremen Thank you for your response. That is a great answer for #1, what about for #2 and #3, when do you use mock.Mock and when do you use mock.patch, because it seems like both can be used in tests. Or why would one use one over another? – 0x5929 Aug 06 '20 at 18:20

1 Answers1

17

I'm not completely sure if I understood your question, but I'll give it a try. As described in the documentation, Mock objects (actually MagickMock instances) are created by using the patch decorator:

from unittest.mock import patch

@patch('some_module.some_object')
def test_something(mocked_object):
    print(mocked_object)

This gives something like:

<MagicMock name='some_object' id='1870192381512'>

This is eqivalent to:

def test_something():
    with patch('some_module.some_object') as mocked_object:
        print(mocked_object)

This gives you the possibility to replace any object by a mock object to avoid calling the actual production code and/or to check how the original object is called (if the object is a function). The reason why using patch (or some similar methods) is preferred is that this ensures that the patch is reverted after the test (or after the context manager scope in the second case), so there are no side effects on other tests or other code.

To cite the documentation:

The patch decorators are used for patching objects only within the scope of the function they decorate. They automatically handle the unpatching for you, even if exceptions are raised. All of these functions can also be used in with statements or as class decorators.

You are also able to create a Mock object manually and assign it to an object - I assume this is what you mean in your question. If you do this instead of using patch, you are responsible to reset the previous state yourself. As this is more error-prone, I would advice to the dedicated methods for patching if possible.

Where this does not matter is in local objects and other mocks. Mocking local objects is seldom needed, but Mock instances are often created in conjunction with patching an object to preserve the instance of a mock object for later check:

@mock.patch('my_functions.MyClass')
def test_object(mock_class):
    arg1 = Mock()
    arg2 = Mock()
    do_something(arg1, arg2)

    # check that do_something creates MyClass with the given arguments 
    mock_class.assert_called_with(arg1, arg2)

In this case the case will only be used as an argument to a mock object, so no reset is needed.

To summarize:

  • patch is a convenience decorator/context manager function to replace objects with mock objects (or other objects) and reset the previous state after finishing or in case of an exception
  • Mock or derived objects are created by mock.patch, and can also be created manually. Manually created mocks are usually only used to patch local functions or other mocks where no reset is needed.
MrBean Bremen
  • 14,916
  • 3
  • 26
  • 46
  • 4
    Thank you for this answer! There are a lot of old answers on this site saying `Mock` is preferred over `patch` with no mention of why. Maybe that's old python2 wisdom? The current unittest docs seem to suggest what you say above: patch is preferred over Mock (though the interface is weirder; Mock is simpler to use) – Mike B Jun 15 '21 at 16:27
  • In Python 2 `mock` was not part of `unittest` - the functionality has been provided in a separate package ([mock](https://pypi.org/project/mock/)), which has later been integrated into Python 3. Apart from that, I see no difference between the usage in Python 2 and Python 3. – MrBean Bremen Jun 15 '21 at 17:59