Mocking dependencies in a Python module
A few days ago, I set out to learn how to mock a dependency in a module I’m testing. Check out this lovely contrived three-file example:
# dependency.py
def thing_to_mock():
return 'mock me pls'
# module.py
from dependency import thing_to_mockdef thing_to_test():
return thing_to_mock()
# test_module.py
import pytest
import moduledef test_thing_to_test():
module.thing_to_test()
# TODO: assert that thing_to_mock() gets called
At Bungalow, we use pytest-mock
, which provides a thin wrapper around unittest.mock
as a keyword arg called mocker
to each test function.
I referred to the official mock
docs, including the “Where to patch” section, to see how to mock a function in an imported dependency, but the examples only cover class mocking. However, mocking a dependency function on an imported module is as simple as providing the path to that function from the reference point of the test file.
Being new to Python, I did not know that imported modules and functions automatically become accessible attributes on the importing module, so I didn’t grok this until I came across this Stack Overflow question and accepted answer.
So the test becomes:
# dependency.py
def thing_to_mock():
return 'mock me pls'
# module.py
from dependency import thing_to_mockdef thing_to_test():
return thing_to_mock()
# test_module.py
import pytest
import moduledef test_thing_to_test(mocker):
mock = mocker.patch('module.thing_to_mock')
module.thing_to_test() mock.assert_called_once()
If the entire dependency is being imported, rather than using the from
syntax, then the patch path changes:
# dependency.py
def thing_to_mock():
return 'mock me pls'# module.py
import dependencydef thing_to_test():
return dependency.thing_to_mock()# test_module.py
import pytest
import moduledef test_thing_to_test(mocker):
mock = mocker.patch('module.dependency.thing_to_mock')
module.thing_to_test() mock.assert_called_once()
If simply using mock
, you can use the @patch
decorator or call mock.patch()
directly — the call is the same either way.
Addendum: Read the docs carefully
The Mock class, an instance of which is returned from mock.patch()
, has several assertion methods, such as assert_called_once_with
, assert_called_with
, and assert_any_call
. These methods may not do what you think!
assert_called_once_with
asserts that the mock was called exactly once, and that the arguments match (not that the function was called once with the arguments provided, as I initially thought).assert_called_once_with
andassert_called_with
only check the last call — this is the one that burned me. To check that the mock was called with a set of arguments at any point, useassert_any_call
.