Skip to content

Pytest crash when exception is raised in fixture teardown and --exitfirst flag is set #9266

Closed
@oleg-kondaurov

Description

@oleg-kondaurov

Discussed in #9213

Originally posted by oleg-kondaurov October 18, 2021

When error is raised in fixture teardown, --exitfirst flag is set, and some additional test is still not started => Pytest crash is observed instead of a report.

Use the following tests/test2.py file to reproduce the issue:

import pytest


class TestT:
    @pytest.fixture(scope='class')
    def fix1(self):
        print('setup 1')
        yield
        print('teardown 1')
        raise Exception('test 1 teardown exception')

    @pytest.fixture(scope='function')
    def fix2(self):
        print('setup 2')
        yield
        print('teardown 2')
        raise Exception('test 2 teardown exception')

    def test1(self, fix1, fix2):
        print('test 1')

    def test2(self):
        print('test 2')

If the --etixfirst flag is not set the test run returns test report with 2 passed, 2 errors, short test summary info and failed tests traces:

 $ py.test tests/test2.py  -s 
======================================================================================================================================================================== test session starts ========================================================================================================================================================================
platform linux -- Python 3.8.10, pytest-6.2.5, py-1.10.0, pluggy-0.13.1
rootdir: /home/okondaurov/GitHub/kyiv-qa-tests, configfile: pytest.ini
plugins: metadata-1.11.0, cov-3.0.0, mock-3.6.1, html-3.1.1, dependency-0.5.1
collected 2 items                                                                                                                                                                                                                                                                                                                                                   

tests/test2.py setup 1
setup 2
test 1
.teardown 2
Etest 2
.teardown 1
E

============================================================================================================================================================================== ERRORS ===============================================================================================================================================================================
_________________________________________________________________________________________________________________________________________________________________ ERROR at teardown of TestT.test1 __________________________________________________________________________________________________________________________________________________________________

self = <tests.test2.TestT object at 0x7f060d412460>

    @pytest.fixture(scope='function')
    def fix2(self):
        print('setup 2')
        yield
        print('teardown 2')
>       raise Exception('test 2 teardown exception')
E       Exception: test 2 teardown exception

tests/test2.py:17: Exception
_________________________________________________________________________________________________________________________________________________________________ ERROR at teardown of TestT.test2 __________________________________________________________________________________________________________________________________________________________________

self = <tests.test2.TestT object at 0x7f060d3f9fd0>

    @pytest.fixture(scope='class')
    def fix1(self):
        print('setup 1')
        yield
        print('teardown 1')
>       raise Exception('test 1 teardown exception')
E       Exception: test 1 teardown exception

tests/test2.py:10: Exception
====================================================================================================================================================================== short test summary info ======================================================================================================================================================================
ERROR tests/test2.py::TestT::test1 - Exception: test 2 teardown exception
ERROR tests/test2.py::TestT::test2 - Exception: test 1 teardown exception
==================================================================================================================================================================== 2 passed, 2 errors in 0.06s ====================================================================================================================================================================

If the --etixfirst flag is set pytest is crashed due to unhandled exception:

$ py.test tests/test2.py  -s --exitfirst
======================================================================================================================================================================== test session starts ========================================================================================================================================================================
platform linux -- Python 3.8.10, pytest-6.2.5, py-1.10.0, pluggy-0.13.1
rootdir: /home/okondaurov/GitHub/kyiv-qa-tests, configfile: pytest.ini
plugins: metadata-1.11.0, cov-3.0.0, mock-3.6.1, html-3.1.1, dependency-0.5.1
collected 2 items                                                                                                                                                                                                                                                                                                                                                   

tests/test2.py setup 1
setup 2
test 1
.teardown 2
Eteardown 1
Traceback (most recent call last):
  File "/home/okondaurov/GitHub/kyiv-qa-tests/venv/bin/py.test", line 8, in <module>
    sys.exit(console_main())
  File "/home/okondaurov/GitHub/kyiv-qa-tests/venv/lib/python3.8/site-packages/_pytest/config/__init__.py", line 185, in console_main
    code = main()
  File "/home/okondaurov/GitHub/kyiv-qa-tests/venv/lib/python3.8/site-packages/_pytest/config/__init__.py", line 162, in main
    ret: Union[ExitCode, int] = config.hook.pytest_cmdline_main(
  File "/home/okondaurov/GitHub/kyiv-qa-tests/venv/lib/python3.8/site-packages/pluggy/hooks.py", line 286, in __call__
    return self._hookexec(self, self.get_hookimpls(), kwargs)
  File "/home/okondaurov/GitHub/kyiv-qa-tests/venv/lib/python3.8/site-packages/pluggy/manager.py", line 93, in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
  File "/home/okondaurov/GitHub/kyiv-qa-tests/venv/lib/python3.8/site-packages/pluggy/manager.py", line 84, in <lambda>
    self._inner_hookexec = lambda hook, methods, kwargs: hook.multicall(
  File "/home/okondaurov/GitHub/kyiv-qa-tests/venv/lib/python3.8/site-packages/pluggy/callers.py", line 208, in _multicall
    return outcome.get_result()
  File "/home/okondaurov/GitHub/kyiv-qa-tests/venv/lib/python3.8/site-packages/pluggy/callers.py", line 80, in get_result
    raise ex[1].with_traceback(ex[2])
  File "/home/okondaurov/GitHub/kyiv-qa-tests/venv/lib/python3.8/site-packages/pluggy/callers.py", line 187, in _multicall
    res = hook_impl.function(*args)
  File "/home/okondaurov/GitHub/kyiv-qa-tests/venv/lib/python3.8/site-packages/_pytest/main.py", line 316, in pytest_cmdline_main
    return wrap_session(config, _main)
  File "/home/okondaurov/GitHub/kyiv-qa-tests/venv/lib/python3.8/site-packages/_pytest/main.py", line 304, in wrap_session
    config.hook.pytest_sessionfinish(
  File "/home/okondaurov/GitHub/kyiv-qa-tests/venv/lib/python3.8/site-packages/pluggy/hooks.py", line 286, in __call__
    return self._hookexec(self, self.get_hookimpls(), kwargs)
  File "/home/okondaurov/GitHub/kyiv-qa-tests/venv/lib/python3.8/site-packages/pluggy/manager.py", line 93, in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
  File "/home/okondaurov/GitHub/kyiv-qa-tests/venv/lib/python3.8/site-packages/pluggy/manager.py", line 84, in <lambda>
    self._inner_hookexec = lambda hook, methods, kwargs: hook.multicall(
  File "/home/okondaurov/GitHub/kyiv-qa-tests/venv/lib/python3.8/site-packages/pluggy/callers.py", line 203, in _multicall
    gen.send(outcome)
  File "/home/okondaurov/GitHub/kyiv-qa-tests/venv/lib/python3.8/site-packages/_pytest/terminal.py", line 803, in pytest_sessionfinish
    outcome.get_result()
  File "/home/okondaurov/GitHub/kyiv-qa-tests/venv/lib/python3.8/site-packages/pluggy/callers.py", line 80, in get_result
    raise ex[1].with_traceback(ex[2])
  File "/home/okondaurov/GitHub/kyiv-qa-tests/venv/lib/python3.8/site-packages/pluggy/callers.py", line 187, in _multicall
    res = hook_impl.function(*args)
  File "/home/okondaurov/GitHub/kyiv-qa-tests/venv/lib/python3.8/site-packages/_pytest/runner.py", line 103, in pytest_sessionfinish
    session._setupstate.teardown_all()
  File "/home/okondaurov/GitHub/kyiv-qa-tests/venv/lib/python3.8/site-packages/_pytest/runner.py", line 412, in teardown_all
    self._pop_and_teardown()
  File "/home/okondaurov/GitHub/kyiv-qa-tests/venv/lib/python3.8/site-packages/_pytest/runner.py", line 387, in _pop_and_teardown
    self._teardown_with_finalization(colitem)
  File "/home/okondaurov/GitHub/kyiv-qa-tests/venv/lib/python3.8/site-packages/_pytest/runner.py", line 405, in _teardown_with_finalization
    self._callfinalizers(colitem)
  File "/home/okondaurov/GitHub/kyiv-qa-tests/venv/lib/python3.8/site-packages/_pytest/runner.py", line 402, in _callfinalizers
    raise exc
  File "/home/okondaurov/GitHub/kyiv-qa-tests/venv/lib/python3.8/site-packages/_pytest/runner.py", line 395, in _callfinalizers
    fin()
  File "/home/okondaurov/GitHub/kyiv-qa-tests/venv/lib/python3.8/site-packages/_pytest/fixtures.py", line 1034, in finish
    raise exc
  File "/home/okondaurov/GitHub/kyiv-qa-tests/venv/lib/python3.8/site-packages/_pytest/fixtures.py", line 1027, in finish
    func()
  File "/home/okondaurov/GitHub/kyiv-qa-tests/venv/lib/python3.8/site-packages/_pytest/fixtures.py", line 941, in _teardown_yield_fixture
    next(it)
  File "/home/okondaurov/GitHub/kyiv-qa-tests/tests/test2.py", line 10, in fix1
    raise Exception('test 1 teardown exception')
Exception: test 1 teardown exception

Metadata

Metadata

Assignees

No one assigned

    Labels

    topic: configrelated to config handling, argument parsing and config filetopic: fixturesanything involving fixtures directly or indirectlytype: bugproblem that needs to be addressed

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions