Search code examples
pythonpython-3.xpython-unittestpatchpython-unittest.mock

What is the difference between using mock.Mock() vs mock.patch(), and when to use one over the other?


  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?

Solution

  • 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.