Search code examples
python-3.xpytestfixtures

How do I create my own pytest fixture?


I would like to create my own pytest fixture where I can insert what I want it to do in the setup and teardown phase.

I am looking for something like this (in this example, i create a file that's needed for the test):

@pytest.fixture
def file(path, content):
    def setup():
        # check that file does NOT exist
        if os.path.isfile(path):
            raise Exception('file already exists')

        # put contents in the file
        with open(path, 'w') as file:
            file.write(content)
    def teardown():
        os.remove(path)

and I would like to be able to use it like this:

def test_my_function(file):
    file('/Users/Me/myapplication/info.txt', 'ham, eggs, orange juice')
    assert my_function('info') == ['ham', 'eggs', 'orange juice']

I am aware there is already a tempdir fixture in pytest that has similar functionality. Unfortunately, that fixture only creates files somewhere within the /tmp directory, and I need files in my application.

Thanks!

UPDATE: I'm getting pretty close. The following almost works, but it doesn't set the PATH variable global to the fixture like I expected. I'm wondering if I can create a class instead of a function for my fixture.

@pytest.fixture
def file(request):
    PATH = None
    def setup(path, content):
        PATH = path

        # check that file does NOT exist
        if os.path.isfile(PATH):
            raise Exception('file already exists')

        # put contents in the file
        with open(PATH, 'w+') as file:
            file.write(content)
    def teardown():
        os.remove(PATH)
    request.addfinalizer(teardown)
    return setup

Solution

  • This is a bit crazy, but here is a solution:

    @pytest.fixture
    def file(request):
        class File:
            def __call__(self, path, content):
                self.path = path
    
                # check that file does NOT exist
                if os.path.isfile(self.path):
                    raise Exception('file already exists')
    
                # put contents in the file
                with open(self.path, 'w+') as file:
                    file.write(content)
            def teardown(self):
                os.remove(self.path)
        obj = File()
        request.addfinalizer(obj.teardown)
        return obj