How to mock the existence of a particular file in python unit test?
Asked Answered
S

3

9

I am writing a unit test for embedded software code in python.

One of the files require a specific file to exist. (e.g. "/dir_name/file_name.txt") otherwise it raises an error.

Normally, this file exists on hardware device and my python code reads this file. When writing unit tests for python code, how can I mock the existence of the file?

tempfile.mkstemp() does not seem to generate the exact path/file name I want, which is/dir_name/file_name.txt. It always adds some random letters.

This is with Python3.4. Is it possible to accomplish this with unittest.mock ?

Somersomers answered 22/10, 2016 at 0:57 Comment(10)
Do you actually need this fine to exist? Or or are you asking how you can mock it out so that whatever it is you are testing thinks it exists? Can you provide a sample of your code and what you are testing? I think I have an idea, but I would like to see what your current approach is.Godunov
No, it does not need to exist. As long as I can make my code believe that the file exists, then it is fine.Somersomers
Excellent. Can you show some of the code to know how to cater the solution? There are different options here, but it would be great to see what your current approach is to know how to give a more relevant solution.Godunov
Another complication is that this happens when I do import module_A. When I am doing this import, it requires the file (or we need to make it believe that the file exists) and that's bit tricky... import module_A is where it raises an exception if the file does not exist.Somersomers
Is it because you are setting your file in the global space? If you do, any code that is in that space will be executed upon importing the module.Godunov
Yes, there is a global object that is defined in module_A and the creation of that object requires the file existence (or we need to fool it to make it believe that the file exists)Somersomers
That is where the complication comes up. The mocking is always going to be too late because of the code that is running upon import.Godunov
can we patch that global object? I don't really need that global object for the unit test. The global object is for the HW that the python runs on.Somersomers
You'd have to see how you can get the patching to happen before the import runs. Which does not seem like something easily done. This is why I typically avoid having code run on import.Godunov
You can mock the open call and any other system calls that deal with that file. But a better approach is to refactor the code under test to inject the file path and/or the file buffer.Culley
S
2

You could create a context manager that creates and deletes the file.

from contextlib import contextmanager

@contextmanager
def mock_file(filepath, content=''):
    with open(filepath, 'w') as f:
        f.write(content)
    yield filepath
    try:
        os.remove(filepath)
    except Exception:
        pass


def test_function():
    with mock_file(r'/dirname/filename.txt'):
        function()
Seabury answered 22/10, 2016 at 1:4 Comment(1)
If in the future, the file actually does exist, this will overwrite it, and not restore the original file when the test finishes. So it's not a true "mock" in that sense.Audiogenic
A
0

This is one of the examples given in unittest's "getting started" page.

For posterity, here's a copy/paste from that page:

DEFAULT = "default"
data_dict = {"file1": "data1",
             "file2": "data2"}

def open_side_effect(name):
    return mock_open(read_data=data_dict.get(name, DEFAULT))()

with patch("builtins.open", side_effect=open_side_effect):
    with open("file1") as file1:
        assert file1.read() == "data1"

    with open("file2") as file2:
        assert file2.read() == "data2"

    with open("file3") as file2:
        assert file2.read() == "default"
Audiogenic answered 11/9, 2023 at 15:43 Comment(0)
P
0

If your function call (eg. your_function_call) uses Path("/dir_name/file_name.txt").exists() to test for the existence of the file then a simple way is:

with patch("pathlib.Path.exists", autospec=True): your_function_call( )

Psychotomimetic answered 12/4, 2024 at 14:26 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.