Is pytest_runtest_teardown called for skipped tests while pytest_runtest_setup is not?

Viewed 728

I have a plugin that implements the following hooks:

def pytest_runtest_setup(item):
    item.config.bla = Bla()

def pytest_runtest_teardown(item):
    item.config.bla.do_bla()
    item.config.bla = None

All works fine until some tests start to throw AttributeError: 'NoneType' object has no attribute 'do_bla' and indeed, item.config.bla is None

This happens in tests which I marked as

@pytest.mark.skip(reason='bla bla')
def test_bla():
    pass

I tried ipdb-ing the setup hook - but it is not called, while the teardown is. Does it make sense that setups are not called for skip tests while teardowns are?

I can wrap my teardown with try, except but I want to verify the root cause...

1 Answers

The problem seems to be that the pytest_runtest_setup hook is implemented by several components in pytest itself, one being the skipping module (_pytest/skipping.py).
The implementation does something like this:

@hookimpl(tryfirst=True)
def pytest_runtest_setup(item):
    ...
    for skip_info in item.iter_markers(name="skip"):
        item._store[skipped_by_mark_key] = True
        if "reason" in skip_info.kwargs:
            skip(skip_info.kwargs["reason"])
        elif skip_info.args:
            skip(skip_info.args[0])
        else:
            skip("unconditional skip")

e.g. if it finds a skip mark, it raises Skipped() (which is basically all that skip does), which is caught only after any pre-test and test hooks would be executed.

I don't know if this intentional, but you obviously have to expect this behavior (which you can easily do in your case by catching the AttributeError, as you wrote).

Related