pythonpytestpython-decorators

Automatic pytest.mark decoration based on fixture


Let's say I have a pytest fixture established in my conftest.py file that looks like:

def live_fixture():
    # network access here...
    pass

I use this same fixture in many test functions, say that test_spam.py has some test functions:

@pytest.mark.live
def test_one(live_fixture):
    assert 1


def test_one():
    assert 2 

@pytest.mark.live
def test_three(live_fixture):
    assert 3

I use the @pytest.mark.live decoration on the first and third test functions because those two tests both depend on the fixture live_fixture, which goes out over the network and does stuff. Rationale: I like having a reliable subset of my tests pass offline, such that e.g.

py.test -m "not live" test_spam.py --blockage

will reliably pass (using the nifty pytest-blockage module to enforce the no-network-access restriction).

But writing out the @pytest.mark.live decoration on each test function which uses the live_fixture here is tedious and error-prone. Is there some way to have that fixture declare that any test function which uses it should automatically have @pytest.mark.live decoration applied to it, or some way to detect inside file test_spam.py that test_one and test_three use that live_fixture and thus should be effectively decorated @pytest.mark.live?


Solution

  • I found another plausible solution, by trying to dig out how pytest.mark works.

    I found class Node has a method "add_marker", which should be the exact method which implement feature pytest.mark. And class Item is extended from Node.

    So my solution is:

    1. Trying to find if the fixture is used by the test.
    2. Let Item object of the test call add_marker

    Example: Add following method in conftest.py

    def pytest_itemcollected(item):
        """ we just collected a test item. """
        if 'live_fixture' in item.fixturenames:
            item.add_marker('live')
    

    I hope at least my answer would inspire somebody to think of a more decent way.