How to Mock open() in Python Using unittest.mock.patch
This code shows how to use unittest.mock.patch with mock_open to test a function that checks if a Git patch can be reverse-applied by reading file content.
Python code
33 linesimport unittest
from unittest.mock import patch, mock_open
def apply_reverse_check(file_path, expected_patch):
"""
Check if a patch can be reverse-applied by comparing file content
with the expected patch's reverse result.
"""
try:
with open(file_path, "r") as f:
content = f.read()
if content == expected_patch["reverse"]:
return "can reverse-apply"
return "cannot reverse-apply"
except FileNotFoundError:
return "file missing"
class TestApplyReverseCheck(unittest.TestCase):
@patch("builtins.open", new_callable=mock_open, read_data="old content")
def test_reverse_check_success(self, mock_file):
result = apply_reverse_check("file.txt", {"reverse": "old content"})
self.assertEqual(result, "can reverse-apply")
@patch("builtins.open", new_callable=mock_open, read_data="new content")
def test_reverse_check_failure(self, mock_file):
result = apply_reverse_check("file.txt", {"reverse": "old content"})
self.assertEqual(result, "cannot reverse-apply")
if __name__ == "__main__":
unittest.main()
Output
..
----------------------------------------------------------------------
Ran 2 tests in 0.002s
OK
How it works
The @patch("builtins.open", new_callable=mock_open, read_data="...") decorator replaces the built-in open with a mock that returns the specified read_data when .read() is called. This lets you test code that reads files without touching the actual filesystem. The apply_reverse_check function reads the file content and compares it with the expected_patch["reverse"] string, returning a status string. By patching open, you can control the file content for each test, verifying both success and failure paths deterministically. This pattern is essential for unit testing functions that interact with Git patches or file operations in isolation.
Common mistakes
- Forgetting to patch the correct target; use `builtins.open` not `open` when patching globally.
- Not passing `new_callable=mock_open`, which leads to a MagicMock that doesn't simulate file reads properly.
- Using `read_data` without ensuring the function actually calls `.read()` — if it iterates lines, behavior differs.
- Forgetting to restore the patch after tests if using manual start/stop instead of the decorator.
Variations
- Use `with patch("builtins.open", mock_open(read_data="..."))` for context-manager style patching.
- Use `pytest` with `monkeypatch` to replace `open` for a more pytest-native approach.
Real-world use cases
- Testing a function that checks whether a Git patch can be cleanly reverted without actually touching the repo.
- Validating file-based configuration loaders in unit tests without requiring fixture files on disk.
- Simulating read-only file access in CI/CD pipelines to verify error handling logic.
Sponsored
More from Git + Python
- Amend Last Commit Message in Python easy
- Bisect Good Bad Automation Script in Python easy
- Build a Simple Log Graph in Python easy
- Bump Semantic Version Git Tag in Python easy
- Count Unique Contributors from Git Shortlog in Python easy
- Create a Mock GitHub Release API in Python for Testing gh CLI easy
Keep learning
Related tutorials and quizzes for this topic.