* `PlaceHolder and ErrorHolder` now support being given result details.

(Robert Collins)

* ``ErrorHolder`` is now just a function - all the logic is in ``PlaceHolder``.
  (Robert Collins)
This commit is contained in:
Robert Collins
2012-04-03 15:28:29 +12:00
parent d091b9d151
commit dd4024983b
3 changed files with 84 additions and 62 deletions

8
NEWS
View File

@@ -7,6 +7,14 @@ Changes and improvements to testtools_, grouped by release.
NEXT
~~~~
Changes
-------
* ``PlaceHolder`` and ``ErrorHolder`` now support being given result details.
(Robert Collins)
* ``ErrorHolder`` is now just a function - all the logic is in ``PlaceHolder``.
(Robert Collins)
0.9.14
~~~~~~

View File

@@ -42,7 +42,10 @@ from testtools.matchers import (
)
from testtools.monkey import patch
from testtools.runtest import RunTest
from testtools.testresult import TestResult
from testtools.testresult import (
ExtendedToOriginalDecorator,
TestResult,
)
wraps = try_import('functools.wraps')
@@ -602,21 +605,30 @@ class PlaceHolder(object):
particularly suitable for being added to TestResults.
"""
def __init__(self, test_id, short_description=None):
failureException = None
def __init__(self, test_id, short_description=None, details=None,
outcome='addSuccess', error=None):
"""Construct a `PlaceHolder`.
:param test_id: The id of the placeholder test.
:param short_description: The short description of the place holder
test. If not provided, the id will be used instead.
:param details: Outcome details as accepted by addSuccess etc.
:param outcome: The outcome to call. Defaults to 'addSuccess'.
"""
self._test_id = test_id
self._short_description = short_description
self._details = details or {}
self._outcome = outcome
if error is not None:
self._details['traceback'] = content.TracebackContent(error, self)
def __call__(self, result=None):
return self.run(result=result)
def __repr__(self):
internal = [self._test_id]
internal = [self._outcome, self._test_id, self._details]
if self._short_description is not None:
internal.append(self._short_description)
return "<%s.%s(%s)>" % (
@@ -636,11 +648,17 @@ class PlaceHolder(object):
def id(self):
return self._test_id
def run(self, result=None):
def _result(self, result):
if result is None:
result = TestResult()
return TestResult()
else:
return ExtendedToOriginalDecorator(result)
def run(self, result=None):
result = self._result(result)
result.startTest(self)
result.addSuccess(self)
outcome = getattr(result, self._outcome)
outcome(self, details=self._details)
result.stopTest(self)
def shortDescription(self):
@@ -650,37 +668,18 @@ class PlaceHolder(object):
return self._short_description
class ErrorHolder(PlaceHolder):
"""A placeholder test that will error out when run."""
def ErrorHolder(test_id, error, short_description=None, details=None):
"""Construct an `ErrorHolder`.
failureException = None
def __init__(self, test_id, error, short_description=None):
"""Construct an `ErrorHolder`.
:param test_id: The id of the test.
:param error: The exc info tuple that will be used as the test's error.
:param short_description: An optional short description of the test.
"""
super(ErrorHolder, self).__init__(
test_id, short_description=short_description)
self._error = error
def __repr__(self):
internal = [self._test_id, self._error]
if self._short_description is not None:
internal.append(self._short_description)
return "<%s.%s(%s)>" % (
self.__class__.__module__,
self.__class__.__name__,
", ".join(map(repr, internal)))
def run(self, result=None):
if result is None:
result = TestResult()
result.startTest(self)
result.addError(self, self._error)
result.stopTest(self)
:param test_id: The id of the test.
:param error: The exc info tuple that will be used as the test's error.
This is inserted into the details as 'traceback' - any existing key
will be overridden.
:param short_description: An optional short description of the test.
:param details: Outcome details as accepted by addSuccess etc.
"""
return PlaceHolder(test_id, short_description=short_description,
details=details, outcome='addError', error=error)
# Python 2.4 did not know how to copy functions.

View File

@@ -77,16 +77,21 @@ class TestPlaceHolder(TestCase):
# repr(placeholder) shows you how the object was constructed.
test = PlaceHolder("test id")
self.assertEqual(
"<testtools.testcase.PlaceHolder(%s)>" % repr(test.id()),
repr(test))
"<testtools.testcase.PlaceHolder('addSuccess', %s, {})>" % repr(
test.id()), repr(test))
def test_repr_with_description(self):
# repr(placeholder) shows you how the object was constructed.
test = PlaceHolder("test id", "description")
self.assertEqual(
"<testtools.testcase.PlaceHolder(%r, %r)>" % (
test.id(), test.shortDescription()),
repr(test))
"<testtools.testcase.PlaceHolder('addSuccess', %r, {}, %r)>" % (
test.id(), test.shortDescription()), repr(test))
def test_repr_custom_outcome(self):
test = PlaceHolder("test id", outcome='addSkip')
self.assertEqual(
"<testtools.testcase.PlaceHolder('addSkip', %r, {})>" % (
test.id()), repr(test))
def test_counts_as_one_test(self):
# A placeholder test counts as one test.
@@ -107,6 +112,17 @@ class TestPlaceHolder(TestCase):
[('startTest', test), ('addSuccess', test), ('stopTest', test)],
log)
def test_supplies_details(self):
details = {'quux':None}
test = PlaceHolder('foo', details=details)
result = ExtendedTestResult()
test.run(result)
self.assertEqual(
[('startTest', test),
('addSuccess', test, details),
('stopTest', test)],
result._events)
def test_call_is_run(self):
# A PlaceHolder can be called, in which case it behaves like run.
test = self.makePlaceHolder()
@@ -127,6 +143,8 @@ class TestPlaceHolder(TestCase):
class TestErrorHolder(TestCase):
# Note that these tests exist because ErrorHolder exists - it could be
# deprecated and dropped at this point.
run_test_with = FullStackRunTest
@@ -158,23 +176,6 @@ class TestErrorHolder(TestCase):
test = ErrorHolder("test id", self.makeException(), "description")
self.assertEqual("description", test.shortDescription())
def test_repr_just_id(self):
# repr(placeholder) shows you how the object was constructed.
error = self.makeException()
test = ErrorHolder("test id", error)
self.assertEqual(
"<testtools.testcase.ErrorHolder(%r, %r)>" % (test.id(), error),
repr(test))
def test_repr_with_description(self):
# repr(placeholder) shows you how the object was constructed.
error = self.makeException()
test = ErrorHolder("test id", error, "description")
self.assertEqual(
"<testtools.testcase.ErrorHolder(%r, %r, %r)>" % (
test.id(), error, test.shortDescription()),
repr(test))
def test_counts_as_one_test(self):
# A placeholder test counts as one test.
test = self.makePlaceHolder()
@@ -186,16 +187,30 @@ class TestErrorHolder(TestCase):
self.assertEqual(test.id(), str(test))
def test_runs_as_error(self):
# When run, a PlaceHolder test records a success.
# When run, an ErrorHolder test records an error.
error = self.makeException()
test = self.makePlaceHolder(error=error)
log = []
test.run(LoggingResult(log))
result = ExtendedTestResult()
log = result._events
test.run(result)
self.assertEqual(
[('startTest', test),
('addError', test, error),
('addError', test, test._details),
('stopTest', test)], log)
def test_supplies_details(self):
details = {'quux':None}
error = self.makeException()
test = ErrorHolder('foo', error, details=details)
result = ExtendedTestResult()
test.run(result)
self.assertEqual(
[('startTest', test),
('addError', test, details),
('stopTest', test)],
result._events)
self.assertTrue('traceback' in details)
def test_call_is_run(self):
# A PlaceHolder can be called, in which case it behaves like run.
test = self.makePlaceHolder()