Become compatible with newer Fixtures _setUp() API.

Previously, when gathering details caused by a setUp failure,
a traceback occurred if the fixture used the newer _setUp().
This also had the side effect of not clearing up fixtures properly.

Change-Id: I9d138e8d559e176867c6e3f4b89f784cf4d29f05
Fixes: https://bugs.launchpad.net/testtools/+bug/1469759
This commit is contained in:
Julian Edwards 2015-11-19 11:04:10 +10:00 committed by Robert Collins
parent cd286b23f2
commit 11e50d3fc2
4 changed files with 61 additions and 4 deletions

View File

@ -19,6 +19,7 @@ The testtools authors are:
* Vincent Ladeuil
* Nikola Đipanov
* Tristan Seligmann
* Julian Edwards
and are collectively referred to as "testtools developers".

4
NEWS
View File

@ -21,6 +21,10 @@ Improvements
report the lack of result as a test error. This ought to make weird
concurrency interaction bugs easier to understand. (Jonathan Lange)
* Previously, when gathering details caused by a setUp() failure,
a traceback occurred if the fixture used the newer _setUp().
This had the side effect of not clearing up fixtures nor gathering details
properly. This is now fixed. (Julian Edwards, #1469759)
2.0.0
~~~~~

View File

@ -26,6 +26,7 @@ from extras import (
try_import,
try_imports,
)
fixtures = try_import('fixtures')
# To let setup.py work, make this a conditional import.
unittest = try_imports(['unittest2', 'unittest'])
@ -49,7 +50,10 @@ from testtools.matchers import (
)
from testtools.matchers._basic import _FlippedEquals
from testtools.monkey import patch
from testtools.runtest import RunTest
from testtools.runtest import (
MultipleExceptions,
RunTest,
)
from testtools.testresult import (
ExtendedToOriginalDecorator,
TestResult,
@ -680,10 +684,22 @@ class TestCase(unittest.TestCase):
"""
try:
fixture.setUp()
except MultipleExceptions as e:
if (fixtures is not None and
e.args[-1][0] is fixtures.fixture.SetupError):
gather_details(e.args[-1][1].args[0], self.getDetails())
raise
except:
exc_info = sys.exc_info()
try:
gather_details(fixture.getDetails(), self.getDetails())
# fixture._details is not available if using the newer
# _setUp() API in Fixtures because it already cleaned up
# the fixture. Ideally this whole try/except is not
# really needed any more, however, we keep this code to
# remain compatible with the older setUp().
if (safe_hasattr(fixture, '_details') and
fixture._details is not None):
gather_details(fixture.getDetails(), self.getDetails())
except:
# Report the setUp exception, then raise the error during
# gather_details.

View File

@ -10,7 +10,10 @@ from testtools import (
content_type,
)
from testtools.compat import _b, _u
from testtools.matchers import Contains
from testtools.matchers import (
Contains,
Equals,
)
from testtools.testresult.doubles import (
ExtendedTestResult,
)
@ -18,7 +21,6 @@ from testtools.testresult.doubles import (
fixtures = try_import('fixtures')
LoggingFixture = try_import('fixtures.tests.helpers.LoggingFixture')
class TestFixtureSupport(TestCase):
def setUp(self):
@ -113,6 +115,40 @@ class TestFixtureSupport(TestCase):
self.assertEqual(['content', 'traceback'], sorted(details))
self.assertEqual('foobar', ''.join(details['content'].iter_text()))
def test_useFixture_details_captured_from__setUp(self):
# Newer Fixtures deprecates setUp() in favour of _setUp().
# https://bugs.launchpad.net/testtools/+bug/1469759 reports that
# this is broken when gathering details from a broken _setUp().
class BrokenFixture(fixtures.Fixture):
def _setUp(self):
fixtures.Fixture._setUp(self)
self.addDetail('broken', content.text_content("foobar"))
raise Exception("_setUp broke")
fixture = BrokenFixture()
class SimpleTest(TestCase):
def test_foo(self):
self.addDetail('foo_content', content.text_content("foo ok"))
self.useFixture(fixture)
result = ExtendedTestResult()
SimpleTest('test_foo').run(result)
self.assertEqual('addError', result._events[-2][0])
details = result._events[-2][2]
self.assertEqual(
['broken', 'foo_content', 'traceback', 'traceback-1'],
sorted(details))
self.expectThat(
''.join(details['broken'].iter_text()),
Equals('foobar'))
self.expectThat(
''.join(details['foo_content'].iter_text()),
Equals('foo ok'))
self.expectThat(
''.join(details['traceback'].iter_text()),
Contains('_setUp broke'))
self.expectThat(
''.join(details['traceback-1'].iter_text()),
Contains('foobar'))
def test_useFixture_original_exception_raised_if_gather_details_fails(self):
# In bug #1368440 it was reported that when a fixture fails setUp
# and gather_details errors on it, then the original exception that