Reading / Writing on Files
Topics on this page:
Reading Files
Let’s say I have a method that returns the number of lines from a file.
class FileReader:
@staticmethod
def count_lines(file_path):
with open(file_path, 'r') as _file:
file_content_list = _file.readlines()
print(file_content_list)
return len(file_content_list)
But I don’t want to open a real file. I wanna mock the opening and the content of the file.
This is elegantly possible with mock_open().
This replace the use of open().
This works with both open() called directly like this:
file = open('file/path', r)
and with a context manager like this:
with open('file/path', r) as _file:
# ...
Using mock_open
See the official documentation for further detail.
We are going to use patch with parameter new=mock_open(), so the target is replaced with a mock_open object.
mock_open() has a parameter called read_data that is a string for the read(), readline() and readlines() methods of the file opened.
Here is how to mock the file opening and reading with a context manager.
with patch('__main__.open', new=mock_open(read_data='Fooooo')) as _file:
# do your call to path 'foo/bar'
_file.assert_called_once_with('foo/bar', 'r')
FAQ about this code
Whatafuck is a context manager? It’s basically using the syntax
with ..... as variable:. More details here.
Whatafuck is that
__main__.open? That, my friend, is the reference for where the object open is being looked up. In the example above, however, that__main__.openis just for illustration, because I wasn’t mocking any specific open(). More details in the official doc.
Whatafuck is that assert_called_once_with? It makes an assertion if the object was called only one time with the respective parameters. Check it out here.
I bet my ass am pretty sure that you are fucking ready to test our method count_lines_from_file() now.
So let’s check out the test code.
import unittest
from unittest.mock import patch, mock_open
from examples.count_lines.file_reader import FileReader
class TestReadFiles(unittest.TestCase):
def test_count_lines(self):
file_content_mock = """Hello World!!
Hello World is in a file.
A mocked file.
He is not real.
But he think he is.
He doesn't know he is mocked"""
fake_file_path = 'file/path/mock'
with patch('examples.count_lines.file_reader.open'.format(__name__),
new=mock_open(read_data=file_content_mock)) as _file:
actual = FileReader().count_lines(fake_file_path)
_file.assert_called_once_with(fake_file_path, 'r')
expected = len(file_content_mock.split('\n'))
self.assertEqual(expected, actual)
See the source code
Writing on Files
Let’s make the simplest. A method that receives a message and write it on a file given a specific file_path.
class FileWriter:
@staticmethod
def write(file_path, content):
with open(file_path, 'w') as file:
file.write(content)
To mock the opening file and writing content on it, we can use mock_open().
The mock for this object will be similar to what we’ve previously seen in Reading Files, with the exception that we don’t need to pass the parameter read_data in mock_open() because we are not retrieving data from the file.
How the assertion will look like?
To answer this question, we need to ask ourselves:
What do we want to test in this function?
A nice test case, in my delusional opinion, will test if a specific file_path was called on open(), with a specific open mode, and if a specific content was written in the file.
The Mock object implements assertions that could help us testing that.
The one that will be useful to us is MockObject.assert_called_once_with().
Let’s take a look on the test?
import unittest
from unittest.mock import patch, mock_open
from examples.write_on_file.file_writer import FileWriter
class TestFileWriter(unittest.TestCase):
def test_file_writer(self):
fake_file_path = "fake/file/path"
content = "Message to write on file to be written"
with patch('examples.write_on_file.file_writer.open', mock_open()) as mocked_file:
FileWriter().write(fake_file_path, content)
# assert if opened file on write mode 'w'
mocked_file.assert_called_once_with(fake_file_path, 'w')
# assert if write(content) was called from the file opened
# in another words, assert if the specific content was written in file
mocked_file().write.assert_called_once_with(content)
In this test, we mock the opening of the file with a context manager.
The variable mocked_file is the mocked opened file.
examples.write_on_file.file_writer.openis the reference for where the objectopen()is being looked up.
Inside the context manager, we can:
- call our actual method
FileWriter().write(fake_file_path, content) - assert if
mocked_filewas opened with the specific file path:fake_file_path, and write open mode:w - assert if
write()frommocked_filewas called with the parametercontent
See the source code.
Congratulations
You’ve just learned how to mock reading and writing on a file without even opening a real one.
That’s a huge reason to celebrate. Congrats!!!

What about now?
- See other examples
- Go to advanced mocking
- Go to the essentials of mocking
- Go to mocking main menu
- Go to summary