The main idea related to mock is that it is an object that will pretend to have the same behaviours of the real object (that you're mocking).
When you mock an open file method, you are creating a new method, that has the same behaviours of this method, and doesn't matter the content of file of this method consume. Because, ideally, the method is designed to have the same behaviour if the file has 1 or 1 thousand of lines.
In case of open
method, it belongs to builtin library, and can be accessed by mock using the reference as builtins.open
. The unittest.mock
has a method mock_open
that do the hard job for us. You just need to pass the data it will use as content for this, mocked, file.
Here is the example you asked.
app.py
def read_lines_of_file(path):
with open(path) as fp:
return fp.readlines()
test_app.py
from unittest.mock import patch, mock_open
from app import read_lines_of_file
def test_readfile_single_line():
# This is the content of your file
data = "This is the single line"
# Here mock copy cat the open object and set a value to result of open()
with patch("builtins.open", mock_open(read_data=data)) as mock_file:
assert len(read_lines_of_file('/some/path/for/file')) == 1
def test_readfile_multiple_lines():
# This is the content of your file
data = """This is the first line.
This is the second line.
This is the third line."""
# Here we are mocking open file method and assig a result for the call of open,
# no matter what we pass as argument for the filename.
with patch("builtins.open", mock_open(read_data=data)) as mock_file:
# Here is the validation that the content we are working is expected (mocked)
assert len(read_lines_of_file('/some/path/for/file')) == 3