Skip to content

Recommended fixture yield implementation doesn't execute teardown if setup raises exception #2508

@samjl

Description

@samjl

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,

# Old method - always executes the teardown code, even when setup raises exception
@pytest.fixture(scope='function')
def setupTeardown(request):
    def fin():
        print "Function teardown"
    request.addfinalizer(fin)
    print "Function setup"
    setupPassed = False
    assert setupPassed, "Argh setup failed"
    yield

Example output:

platform linux2 -- Python 2.7.6, pytest-3.1.2, py-1.4.34, pluggy-0.4.0
rootdir: /home/slea1/workspace/sessions, inifile:
collected 1 items 
testcases/testDir2/test_cnet-3_pytest_Fixtures_bug.py 
Function setup
E
Function teardown
========================================================== short test summary info ==========================================================
ERROR testcases/testDir2/test_cnet-3_pytest_Fixtures_bug.py::test_fixtureSetupFail
================================================================== ERRORS ===================================================================
__________________________________________________ ERROR at setup of test_fixtureSetupFail __________________________________________________
request = <SubRequest 'setupTeardown' for <Function 'test_fixtureSetupFail'>>
    @pytest.fixture(scope='function')
    def setupTeardown(request):
        def fin():
            print "\nFunction teardown"
        request.addfinalizer(fin)
        print "\nFunction setup"
        setupPassed = False
>       assert setupPassed, "Argh setup failed"
E       AssertionError: Argh setup failed
E       assert False
testcases/testDir2/test_cnet-3_pytest_Fixtures_bug.py:23: AssertionError

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.

# New method - doesn't execute teardown if exception caught in setup
@pytest.fixture(scope='function')
def setupTeardown(request):
    print "\nFunction setup"
    setupPassed = False
    assert setupPassed, "Argh setup failed"
    yield
    # This teardown doesn't execute if setup fails
    print "\nFunction teardown"

Example output:

platform linux2 -- Python 2.7.6, pytest-3.1.2, py-1.4.34, pluggy-0.4.0
rootdir: /home/slea1/workspace/sessions, inifile:
collected 1 items 
testcases/testDir2/test_cnet-3_pytest_Fixtures_bug.py 
Function setup
E
========================================================== short test summary info ==========================================================
ERROR testcases/testDir2/test_cnet-3_pytest_Fixtures_bug.py::test_fixtureSetupFail
================================================================== ERRORS ===================================================================
__________________________________________________ ERROR at setup of test_fixtureSetupFail __________________________________________________
request = <SubRequest 'setupTeardown' for <Function 'test_fixtureSetupFail'>>
    @pytest.fixture(scope='function')
    def setupTeardown(request):
        print "\nFunction setup"
        setupPassed = False
>       assert setupPassed, "Argh setup failed"
E       AssertionError: Argh setup failed
E       assert False
testcases/testDir2/test_cnet-3_pytest_Fixtures_bug.py:8: AssertionError

Notice that the "Function teardown" is not printed.

Test code used in the above examples:

# session_setupPass_teardownPass, module_setupPass_teardownPass, class_setupPass_teardownPass, setupPass_teardownPass
def test_fixtureSetupFail(setupTeardown):
    print "Test function executing..."
    print "Test function complete"

pip list

Package      Version
------------ -------
asn1crypto   0.22.0 
bcrypt       3.1.3  
cffi         1.10.0 
colored      1.3.5  
config       0.3.9  
cryptography 1.9    
enum34       1.1.6  
idna         2.5    
ipaddress    1.0.18 
paramiko     2.2.1  
pip          9.0.1  
py           1.4.34 
pyasn1       0.2.3  
pycparser    2.17   
PyNaCl       1.1.2  
pytest       3.1.2  
scp          0.10.2 
setuptools   36.0.1 
six          1.10.0 
wheel        0.29.0

python version: 2.7.6
Operating system: Kubuntu 14.04

Related to issues: #2195, #2440

Metadata

Metadata

Assignees

No one assigned

    Labels

    type: docsdocumentation improvement, missing or needing clarification

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions