Search code examples
pythonmockingfilesystemspython-unittest.mockpyfakefs

Patching over local JSON file in unit testing


I have some Python code that loads in a local JSON file:

with open("/path/to/file.json") as f:
    json_str = f.read()
    # Now do stuff with this JSON string

In testing, I want to patch that JSON file to be a JSON file located in my repo's test directory ("/path/to/repo/test/fake_file.json").

How can I go about doing that?

One other requirement is I actually have a version of "/path/to/file.json" locally, but I don't want to change it. I want it patched over at test time, and unpatched upon test completion.

Note: I use pytest, and it seems like the plug-in pyfakefs would do this. Sadly, I can't figure out how to get it to patch in another local file (from within my repo's test directory). I am open to solutions using vanilla Python 3.10+ and/or pyfakefs.


Solution

  • With pyfakefs, you can map real files into the fake file system. In your case, you can use add_real_file:

    def test_json(fs):
        fs.add_real_file("/path/to/repo/test/fake_file.json",
                         target_path="/path/to/file.json")
        assert os.path.exists("/path/to/file.json")
    

    This will map your existing file into target_path in the fake file system (if target_path is not given, it will map it to the same location as the source file). It does not matter if there is a real file at the same location, as the real file system will be ignored in the fake file system. If you read "/path/to/file.json" in your test code, it will actually read "/path/to/repo/test/fake_file.json" (mapped files are only read on demand).

    Note that by default the file is mapped read only, so if you want to change it in your tested code, you have to set read_only=False in the mapping call. This will make the file in the fake file system writable, though writing to it will not touch the file in the real file system, of course.

    Disclaimer:
    I'm a contributor to pyfakefs.