Traditional mocking with unittest.mock often requires repetitive setup and teardown code, which can make test code harder to read and maintain.
pytest-mock addresses this issue by leveraging pytest’s fixture system, simplifying the mocking process and reducing boilerplate code.
Consider the following example that demonstrates the difference between unittest.mock and pytest-mock.
Using unittest.mock:
%%writefile test_rm_file.py
from unittest.mock import patch
import os
def rm_file(filename):
os.remove(filename)
def test_with_unittest_mock():
with patch("os.remove") as mock_remove:
rm_file("file")
mock_remove.assert_called_once_with("file")
Using pytest-mock:
%%writefile test_rm_file.py
import os
def rm_file(filename):
os.remove(filename)
def test_unix_fs(mocker):
mocker.patch("os.remove")
rm_file("file")
os.remove.assert_called_once_with("file")
Key differences:
- Setup: pytest-mock uses the
mocker
fixture, automatically provided by pytest, eliminating the need to import patching utilities. - Patching: With pytest-mock, you simply call
mocker.patch('os.remove')
, whereas unittest.mock requires a context manager or decorator. - Cleanup: pytest-mock automatically undoes mocking after the test, while unittest.mock relies on the context manager for cleanup.
- Accessing mocks: pytest-mock allows direct access to the patched function (e.g.,
os.remove.assert_called_once_with()
), while unittest.mock requires accessing the mock through a variable (e.g.,mock_remove.assert_called_once_with()
).