diff --git a/CHANGELOG b/CHANGELOG index d859cad21..a25705ad4 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,10 @@ Unreleased ----------------------------------- +- fix issue287 by running all finalizers but saving the exception + from the last failing finalizer and re-raising it so teardown will + still have failed. + - fix issue384 by removing the trial support code since the unittest compat enhancements allow trial to handle it on its own diff --git a/_pytest/runner.py b/_pytest/runner.py index 9abc9a7fe..345080db0 100644 --- a/_pytest/runner.py +++ b/_pytest/runner.py @@ -328,9 +328,17 @@ class SetupState(object): def _callfinalizers(self, colitem): finalizers = self._finalizers.pop(colitem, None) + exc = None while finalizers: fin = finalizers.pop() - fin() + try: + fin() + except KeyboardInterrupt: + raise + except: + exc = py.std.sys.exc_info() + if exc: + py.builtin._reraise(*exc) def _teardown_with_finalization(self, colitem): self._callfinalizers(colitem) diff --git a/testing/test_runner.py b/testing/test_runner.py index 9b73e2ab2..8a6f4f839 100644 --- a/testing/test_runner.py +++ b/testing/test_runner.py @@ -43,6 +43,21 @@ class TestSetupState: pytest.raises(ValueError, lambda: ss.prepare(item)) pytest.raises(ValueError, lambda: ss.prepare(item)) + def test_teardown_multiple_one_fails(self, testdir): + r = [] + def fin1(): r.append('fin1') + def fin2(): raise Exception('oops') + def fin3(): r.append('fin3') + item = testdir.getitem("def test_func(): pass") + ss = runner.SetupState() + ss.addfinalizer(fin1, item) + ss.addfinalizer(fin2, item) + ss.addfinalizer(fin3, item) + with pytest.raises(Exception) as err: + ss._callfinalizers(item) + assert err.value.args == ('oops',) + assert r == ['fin3', 'fin1'] + class BaseFunctionalTests: def test_passfunction(self, testdir):