Last active
February 17, 2024 09:09
-
-
Save rnag/0a73feb229ae580e545903ea3c040a01 to your computer and use it in GitHub Desktop.
pytest: mock builtin file open()
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Prerequisites: | |
# $ pip install pytest pytest-mock | |
from functools import cache | |
from unittest.mock import MagicMock, mock_open | |
import pytest | |
from pytest_mock import MockerFixture | |
class FileMock(MagicMock): | |
def __init__(self, mocker: MagicMock = None, **kwargs): | |
super().__init__(**kwargs) | |
if mocker: | |
self.__dict__ = mocker.__dict__ | |
# configure mock object to replace the use of open(...) | |
# note: this is useful in scenarios where data is written out | |
_ = mock_open(mock=self) | |
@property | |
def read_data(self): | |
return self.side_effect | |
@read_data.setter | |
def read_data(self, mock_data: str): | |
"""set mock data to be returned when `open(...).read()` is called.""" | |
self.side_effect = mock_open(read_data=mock_data) | |
@property | |
@cache | |
def write_calls(self): | |
"""a list of calls made to `open().write(...)`""" | |
handle = self.return_value | |
write: MagicMock = handle.write | |
return write.call_args_list | |
@property | |
def write_lines(self) -> str: | |
"""a list of written lines (as a string)""" | |
return ''.join([c[0][0] for c in self.write_calls]) | |
@pytest.fixture | |
def mock_file_open(mocker: MockerFixture) -> FileMock: | |
return FileMock(mocker.patch('builtins.open')) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from unittest.mock import call | |
def test_mock_file_open_and_read(mock_file_open): | |
mock_file_open.read_data = 'hello\nworld!' | |
with open('/my/file/here', 'r') as in_file: | |
assert in_file.readlines() == ['hello\n', 'world!'] | |
mock_file_open.assert_called_with('/my/file/here', 'r') | |
def test_mock_file_open_and_write(mock_file_open): | |
with open('/out/file/here', 'w') as f: | |
f.write('hello\n') | |
f.write('world!\n') | |
f.write('--> testing 123 :-)') | |
mock_file_open.assert_called_with('/out/file/here', 'w') | |
assert call('world!\n') in mock_file_open.write_calls | |
assert mock_file_open.write_lines == """\ | |
hello | |
world! | |
--> testing 123 :-) | |
""".rstrip() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment