Search code examples
unit-testingmockingmonkeypatching

How can I use mocking/patching for changing the local directory variable inside a class method to avoid writing test output files into it?


I have an object as follows with a to_json method that I'd like to write a test for.

import networkx as nx

class Example:
    def __init__(self, graph):
        self.graph = graph

    def to_json(self):
        data = nx.readwrite.node_link_data(self.graph)
        filepath = os.path.join('~/.cache/product', 'some_file_name.txt')
        with open(filepath, "w") as outfile:
            json.dump(data, outfile)
        return filepath

When running the unit test for to_json, I don't want to write the output file to the ~/.cache/product directory but rather /tmp/product directory. How can I use achieve this using mocking/patching?

My current test setup looks something like:

def test_example_to_json():
    ex = Example(graph={}) # Some graph
    filepath = ex.to_json() # This is the problematic step since the file is being written to ~/.cache/product
    with open(filepath, "r") as infile:
        assert json.load(infile) == {}

Any advice here would be appreciated.


Solution

  • It is not possible to change the filepath variable and then have the function continue with the rest of the computation via mocking/patching.

    One solution here that worked for me is as follows: I defined an environment variable called CACHE_DIR and used that to get the cache directory. Monkeypatch does allow you to use monkeypatch.setenv("CACHE_DIR", "/tmp/product").

    import networkx as nx
    
    
    class Example:
        def __init__(self, graph):
            self.graph = graph
    
        def to_json(self):
            data = nx.readwrite.node_link_data(self.graph)
            filepath = os.path.join(os.getenv('CACHE_DIR'), 'some_file_name.txt')
            with open(filepath, "w") as outfile:
                json.dump(data, outfile)
            return filepath
    

    with the following unittest:

    import pytest
    
    
    def test_example_to_json(monkeypatch):
        ex = Example(graph={})
    
        monkeypatch.setenv("CACHE_DIR", "/tmp/product")
        filepath = ex.to_json() 
        with open(filepath, "r") as infile:
            assert json.load(infile) == {}