-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Recommended fixture yield implementation doesn't execute teardown if setup raises exception #2508
Comments
Thanks for the detailed description @samjl. You are right and both methods have the difference you point out. Unfortunately I think there's no way to actually fix this because of how By using Using I think we should update the docs to reflect that difference as suggested in #2195. I still would like to recommend Btw, it was never our intention to eventually remove |
Great, thanks for the update. We do a lot of embedded software testing where it is ideal to use a setup fixture(s) to perform a fairly complex setup before a test or set of tests. If the setup subsequently fails it is convenient for us to go through the same teardown process that a successful test would have performed to ensure it is restored to the previous default configuration before the next set of tests. Rather than using addfinalizer I could create a teardown function that could be called after the yield and if the setup code fails (by placing the setup in a try...except). Something like this perhaps: @pytest.fixture(scope='function')
def setupConfig(request):
try:
print "Function setup"
setupPassed = False
assert setupPassed, "Argh setup failed"
except Exception as e:
# Teardown the failed configuration and re-raise the exception
teardownConfig()
raise e
yield
teardownConfig()
def teardownConfig():
print "Teardown code..."
def test_fixtureSetupFail(setupConfig):
print "Test function executing..."
print "Test function complete" Maybe this describes the flow a little better? I agree that in most cases simply using yield is preferred as it better describes the flow. |
I see, thanks. This is a perfect case where multiple
This is a matter of opinion of course, but I think if you already isolated the teardown code into a function you might as well just call @pytest.fixture(scope='function')
def setupConfig(request):
print "Function setup"
request.addfinalizer(teardownConfig)
setupPassed = False
assert setupPassed, "Argh setup failed"
return |
Yes I think that is the neatest solution. Thanks very much for your assistance. |
Using fixtures for setup and teardown:
Difference between older addfinalizer approach and recommended approach with yield only.
Note: The old method described here does still work (as mentioned in the documentation note), but I wish to highlight the different behaviour and the usefulness of the old method before the old method is removed entirely.
Current recommendation as documented in the second note here https://docs.pytest.org/en/latest/fixture.html#fixture-finalization-executing-teardown-code. If this method (do not add finalizer) is used and the setup code raises an exception then the teardown code is not executed.
Old behaviour (no longer recommended), using request.addfinalizer:
If setup code (before yield) raises an exception then the teardown code (after yield) is executed as long as addfinalizer is before the setup code as below,
Example output:
Notice that the teardown code "Function teardown" is executed after the exception is raised.
Recommended method in documentation (do not use addfinalizer)
If setup raises an exception the teardown code is not executed.
Example output:
Notice that the "Function teardown" is not printed.
Test code used in the above examples:
pip list
python version: 2.7.6
Operating system: Kubuntu 14.04
Related to issues: #2195, #2440
The text was updated successfully, but these errors were encountered: