0

I see plenty of examples of mock open online, but I would say the syntax looks very confusing and nobody explains, if I have a file with several lines of text that I want to mock, where I store/put those lines. The difference between this question and others that have been posted is that it is not clear to me in other questions WHERE I should store the text of the file to mocked. Additionally, I would like to use an assertRaises unit test with it.

For example, here are lines of a file that should be mocked: “This is a file

11 15 27277 28183 29199 Hello”

Would appreciate an example of the syntax I would use to lock this file and test it with the unit test library!

DWW
  • 33
  • 3
  • The linked duplicate has examples. If none of them seem applicable to your situation, you might want to post a question that includes the example code that you're trying to test. – Samwise May 08 '23 at 18:39
  • I don't understand how to use the syntactical examples in the link to mock specifically, for example, the text I outlined here. Where it says "write something? Is that where file text goes? Also having trouble wrapping my mind around how to implement this in an assertRaises unit test. – DWW May 08 '23 at 18:50
  • Look at the top rated answer: https://stackoverflow.com/a/34677735/3799759 See where it says `assert open("path/to/open").read() == "data"`? That's a test that asserts that the mock file contains the text `"data"`. Once you understand how that example works (and where the string `"data"` comes from in the mock `open`), you can apply it to your example. – Samwise May 08 '23 at 19:10
  • For storing multi-line strings, consider, "\n", triple-quoted strings or file storage. – Joooeey May 12 '23 at 18:03

1 Answers1

0

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
Mauro Baraldi
  • 6,346
  • 2
  • 32
  • 43