Search code examples
pythonpytest

Adding fixtures to marked tests


I write tests using pytest. I need to do certain things before and after some tests. How can I automatically set the some_fixture to the test function if it is marked with some_marker?

To implement this, I wrote a context manager + fixture.

# conftest.py

class ContextManager:
    def __init__(self, some_args):
        self.some_args = some_args

    def __enter__(self):
        pass    # do something

    def __exit__(self, exc_type, exc_val, exc_tb):
        pass    # do something


@pytest.fixture
def some_fixture(request):
    some_args = request.node.get_closest_marker("some_marker").kwargs.get("some_args")

    with ContextManager(some_args):
        yield


def pytest_configure(config):
    config.addinivalue_line("markers", "some_marker(some_args): ...")

But this is inconvenient because I need to constantly specify the fixture.

# module_test.py
@pytest.mark.some_marker(some_args=[...])
def test_function(some_fixture):
    pass

Solution

  • If you don't want to add the fixture name manually, you can do so during the item collection. You can access and change the fixture names of an item via Function.fixturenames (that is for some reason not listed in the documentation for Function, but mentioned elsewhere, so I guess it is part of the API):

    conftest.py

    def pytest_collection_modifyitems(items):
        for item in items:
            if item.get_closest_marker("some_marker"):
                item.fixturenames.append("some_fixture")
    

    module_test.py

    @pytest.mark.some_marker(some_args=[...])
    def test_function():
        pass
    

    As long as you don't need to access the fixture by name in your test, this should work.