Ensure all finalizations are run when one fails

Fixes issue287.
This commit is contained in:
Floris Bruynooghe 2013-11-19 17:26:18 +00:00
parent 9b21d3f206
commit 72752165df
3 changed files with 28 additions and 1 deletions

View File

@ -1,6 +1,10 @@
Unreleased 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 - fix issue384 by removing the trial support code
since the unittest compat enhancements allow since the unittest compat enhancements allow
trial to handle it on its own trial to handle it on its own

View File

@ -328,9 +328,17 @@ class SetupState(object):
def _callfinalizers(self, colitem): def _callfinalizers(self, colitem):
finalizers = self._finalizers.pop(colitem, None) finalizers = self._finalizers.pop(colitem, None)
exc = None
while finalizers: while finalizers:
fin = finalizers.pop() 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): def _teardown_with_finalization(self, colitem):
self._callfinalizers(colitem) self._callfinalizers(colitem)

View File

@ -43,6 +43,21 @@ class TestSetupState:
pytest.raises(ValueError, lambda: ss.prepare(item)) pytest.raises(ValueError, lambda: ss.prepare(item))
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: class BaseFunctionalTests:
def test_passfunction(self, testdir): def test_passfunction(self, testdir):