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
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With