Mock vs MagicMock in Python
In Python’s unittest.mock module, two prominent classes used for creating mock objects are Mock and MagicMock.
The Mock class offers a basic foundation, allowing you to craft a mock object that can imitate virtually any other object.
MagicMock, on the other hand, is an enriched subclass of Mock.
Beyond inheriting all capabilities of Mock, it predefines most of Python’s “magic” or “dunder” methods (like __getitem__, __setitem__, __iter__, and more).
In a nutshell, while Mock provides essential mocking functionalities, MagicMock elevates them to seamlessly emulate more intricate Python behaviours.
The pytest-mock plugin is built on top of the unittest.mock module.
So, by default, pytest-mock uses MagicMock.
What is the Difference Between Mock and Patch?
- Mock: A
Mockis a standalone object used to simulate the behaviour of functions or objects. It allows you to set up specific behaviours for method calls, like returning values or raising exceptions.
from unittest.mock import Mock
mock_obj = Mock()
mock_obj.some_method.return_value = 42
result = mock_obj.some_method()
assert result == 42- Patch:
patchis a context manager or decorator that temporarily replaces a function or object with a mock during a test. It’s particularly handy for mocking external dependencies.
from unittest.mock import patch
def external_function():
# Some external service call
pass
@patch('module_name.external_function')
def test_function(mock_external):
mock_external.return_value = "Mocked data"
result = external_function()
assert result == "Mocked data"In summary, Mock creates individual mock objects, while patch temporarily replaces real objects/functions with mocks during tests, helping isolate your code and control its behaviour.
Mocking exceptions
def test_remove_directory_directory_not_found_exception(mocker):
"""
Test that a FileNotFoundError is raised when attempting to remove a directory that does not exist.
"""
# Arrange
mocker.patch("shutil.rmtree", side_effect=FileNotFoundError)
# Assert
with pytest.raises(FileNotFoundError):
remove_directory("/tmp/test")We can mock exceptions too, just mock the corrensponding file.