Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a guarantee that code after yield will be executed?

Let's say we have a fixture that allocated some unmanaged resources and releases them like in the following example:

@pytest.fixture
def resource():
    res = driver.Instance()
    yield res

    res.close()

Is there a guarantee that the resource will be released even if something bad happens during the test that utilizes that fixture?

If there is no such guarantee, maybe the following pattern will be better?

@pytest.fixture
def resource(q):
    res = driver.Instance()

    def finalize():
        res.close()

    q.addfinalizer(finalize())
    return res
like image 883
lutar Avatar asked Sep 03 '25 17:09

lutar


1 Answers

It depends on what happens before yield:

If a yield fixture raises an exception before yielding, pytest won’t try to run the teardown code after that yield fixture’s yield statement. But, for every fixture that has already run successfully for that test, pytest will still attempt to tear them down as it normally would.

You say, "even if something bad happens during the test that utilizes that fixture", which implies that the yield has executed. As long as the fixture yields, pytest will attempt to perform the teardown.

I don't think manually finalizing offers any further guarantees:

While yield fixtures are considered to be the cleaner and more straightforward option, there is another choice, and that is to add “finalizer” functions directly to the test’s request-context object. It brings a similar result as yield fixtures, but requires a bit more verbosity.

The section on safe fixtures offers some good tips on how to handle teardown code safely, nicely summarized by this line:

The safest and simplest fixture structure requires limiting fixtures to only making one state-changing action each, and then bundling them together with their teardown code

like image 169
Chris Avatar answered Sep 05 '25 09:09

Chris