summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Foord <fuzzyman@voidspace.org.uk>2010-02-10 15:51:42 (GMT)
committerMichael Foord <fuzzyman@voidspace.org.uk>2010-02-10 15:51:42 (GMT)
commit34c9462d713275762803f102a68f23dd2bb7460a (patch)
treeb56e5520cce62534e26f55285f1ded54de3caa06
parent99f69ee7a1cf4d032d420ad69d22bd44b8cf6cc8 (diff)
downloadcpython-34c9462d713275762803f102a68f23dd2bb7460a.zip
cpython-34c9462d713275762803f102a68f23dd2bb7460a.tar.gz
cpython-34c9462d713275762803f102a68f23dd2bb7460a.tar.bz2
Merged revisions 78130 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk ........ r78130 | michael.foord | 2010-02-10 14:25:12 +0000 (Wed, 10 Feb 2010) | 1 line Issue 7893 and Issue 7588 ........
-rw-r--r--Doc/library/unittest.rst32
-rw-r--r--Lib/test/test_unittest.py55
-rw-r--r--Lib/unittest/__init__.py5
-rw-r--r--Lib/unittest/case.py17
-rw-r--r--Lib/unittest/result.py5
-rw-r--r--Lib/unittest/runner.py32
-rw-r--r--Misc/NEWS7
7 files changed, 107 insertions, 46 deletions
diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst
index 72d7dec..effb116 100644
--- a/Doc/library/unittest.rst
+++ b/Doc/library/unittest.rst
@@ -195,7 +195,7 @@ individual tests are defined with methods whose names start with the letters
represent tests.
The crux of each test is a call to :meth:`~TestCase.assertEqual` to check for an
-expected result; :meth:`~TestCase.assert_` to verify a condition; or
+expected result; :meth:`~TestCase.assertTrue` to verify a condition; or
:meth:`~TestCase.assertRaises` to verify that an expected exception gets raised.
These methods are used instead of the :keyword:`assert` statement so the test
runner can accumulate all test results and produce a report.
@@ -677,6 +677,7 @@ Test cases
.. deprecated:: 3.1
:meth:`failUnless`.
+ :meth:`assert_`; use :meth:`assertTrue`.
.. method:: assertEqual(first, second, msg=None)
@@ -1067,14 +1068,13 @@ Test cases
Returns a description of the test, or :const:`None` if no description
has been provided. The default implementation of this method
returns the first line of the test method's docstring, if available,
- along with the method name.
-
- .. versionchanged:: 3.1
- In earlier versions this only returned the first line of the test
- method's docstring, if available or the :const:`None`. That led to
- undesirable behavior of not printing the test name when someone was
- thoughtful enough to write a docstring.
+ or :const:`None`.
+ .. versionchanged:: 3.1,3.2
+ In 3.1 this was changed to add the test name to the short description
+ even in the presence of a docstring. This caused compatibility issues
+ with unittest extensions and adding the test name was moved to the
+ :class:`TextTestResult`.
.. method:: addTypeEqualityFunc(typeobj, function)
@@ -1517,6 +1517,14 @@ Loading and running tests
The default implementation appends the test to the instance's
:attr:`unexpectedSuccesses` attribute.
+.. class:: TextTestResult(stream, descriptions, verbosity)
+
+ A concrete implementation of :class:`TestResult` used by the
+ :class:`TextTestRunner`.
+
+ .. versionadded:: 3.2
+ This class was previously named ``_TextTestResult``. The old name still
+ exists as an alias but is deprecated.
.. data:: defaultTestLoader
@@ -1525,7 +1533,7 @@ Loading and running tests
instead of repeatedly creating new instances.
-.. class:: TextTestRunner(stream=sys.stderr, descriptions=True, verbosity=1)
+.. class:: TextTestRunner(stream=sys.stderr, descriptions=True, verbosity=1, runnerclass=None)
A basic test runner implementation which prints results on standard error. It
has a few configurable parameters, but is essentially very simple. Graphical
@@ -1537,6 +1545,12 @@ Loading and running tests
It is not intended to be called directly, but can be overridden in
subclasses to provide a custom ``TestResult``.
+ ``_makeResult()`` instantiates the class or callable passed in the
+ ``TextTestRunner`` constructor as the ``resultclass`` argument. It
+ defaults to :class::`TextTestResult` if no ``resultclass`` is provided.
+ The result class is instantiated with the following arguments::
+
+ stream, descriptions, verbosity
.. function:: main(module='__main__', defaultTest=None, argv=None, testRunner=None, testLoader=unittest.loader.defaultTestLoader, exit=True, verbosity=1)
diff --git a/Lib/test/test_unittest.py b/Lib/test/test_unittest.py
index e5219fd..0727931 100644
--- a/Lib/test/test_unittest.py
+++ b/Lib/test/test_unittest.py
@@ -2044,6 +2044,35 @@ class Test_TestResult(TestCase):
self.assertTrue(test_case is test)
self.assertIsInstance(formatted_exc, str)
+ def testGetDescriptionWithoutDocstring(self):
+ result = unittest.TextTestResult(None, True, None)
+ self.assertEqual(
+ result.getDescription(self),
+ 'testGetDescriptionWithoutDocstring (' + __name__ +
+ '.Test_TestResult)')
+
+ def testGetDescriptionWithOneLineDocstring(self):
+ """Tests getDescription() for a method with a docstring."""
+ result = unittest.TextTestResult(None, True, None)
+ self.assertEqual(
+ result.getDescription(self),
+ ('testGetDescriptionWithOneLineDocstring '
+ '(' + __name__ + '.Test_TestResult)\n'
+ 'Tests getDescription() for a method with a docstring.'))
+
+ def testGetDescriptionWithMultiLineDocstring(self):
+ """Tests getDescription() for a method with a longer docstring.
+ The second line of the docstring.
+ """
+ result = unittest.TextTestResult(None, True, None)
+ self.assertEqual(
+ result.getDescription(self),
+ ('testGetDescriptionWithMultiLineDocstring '
+ '(' + __name__ + '.Test_TestResult)\n'
+ 'Tests getDescription() for a method with a longer '
+ 'docstring.'))
+
+
### Support code for Test_TestCase
################################################################
@@ -2458,18 +2487,13 @@ class Test_TestCase(TestCase, TestEquality, TestHashing):
self.assertEqual(events, expected)
def testShortDescriptionWithoutDocstring(self):
- self.assertEqual(
- self.shortDescription(),
- 'testShortDescriptionWithoutDocstring (' + __name__ +
- '.Test_TestCase)')
+ self.assertIsNone(self.shortDescription())
def testShortDescriptionWithOneLineDocstring(self):
"""Tests shortDescription() for a method with a docstring."""
self.assertEqual(
self.shortDescription(),
- ('testShortDescriptionWithOneLineDocstring '
- '(' + __name__ + '.Test_TestCase)\n'
- 'Tests shortDescription() for a method with a docstring.'))
+ 'Tests shortDescription() for a method with a docstring.')
def testShortDescriptionWithMultiLineDocstring(self):
"""Tests shortDescription() for a method with a longer docstring.
@@ -2480,10 +2504,8 @@ class Test_TestCase(TestCase, TestEquality, TestHashing):
"""
self.assertEqual(
self.shortDescription(),
- ('testShortDescriptionWithMultiLineDocstring '
- '(' + __name__ + '.Test_TestCase)\n'
'Tests shortDescription() for a method with a longer '
- 'docstring.'))
+ 'docstring.')
def testAddTypeEqualityFunc(self):
class SadSnake(object):
@@ -3472,6 +3494,19 @@ class Test_TextTestRunner(TestCase):
# StringIO objects never compare equal, a cheap test instead.
self.assertEqual(obj.stream.getvalue(), stream.getvalue())
+ def test_resultclass(self):
+ def MockResultClass(*args):
+ return args
+ STREAM = object()
+ DESCRIPTIONS = object()
+ VERBOSITY = object()
+ runner = unittest.TextTestRunner(STREAM, DESCRIPTIONS, VERBOSITY,
+ resultclass=MockResultClass)
+ self.assertEqual(runner.resultclass, MockResultClass)
+
+ expectedresult = (runner.stream, DESCRIPTIONS, VERBOSITY)
+ self.assertEqual(runner._makeResult(), expectedresult)
+
class TestDiscovery(TestCase):
diff --git a/Lib/unittest/__init__.py b/Lib/unittest/__init__.py
index e0c64d4..c12e669 100644
--- a/Lib/unittest/__init__.py
+++ b/Lib/unittest/__init__.py
@@ -60,4 +60,7 @@ from .suite import TestSuite
from .loader import (TestLoader, defaultTestLoader, makeSuite, getTestCaseNames,
findTestCases)
from .main import TestProgram, main
-from .runner import TextTestRunner
+from .runner import TextTestRunner, TextTestResult
+
+# deprecated
+_TextTestResult = TextTestResult
diff --git a/Lib/unittest/case.py b/Lib/unittest/case.py
index cf180d7..cd0764d 100644
--- a/Lib/unittest/case.py
+++ b/Lib/unittest/case.py
@@ -229,18 +229,15 @@ class TestCase(object):
return result.TestResult()
def shortDescription(self):
- """Returns both the test method name and first line of its docstring.
+ """Returns a one-line description of the test, or None if no
+ description has been provided.
- If no docstring is given, only returns the method name.
+ The default implementation of this method returns the first line of
+ the specified test method's docstring.
"""
- desc = str(self)
- doc_first_line = None
+ doc = self._testMethodDoc
+ return doc and doc.split("\n")[0].strip() or None
- if self._testMethodDoc:
- doc_first_line = self._testMethodDoc.split("\n")[0].strip()
- if doc_first_line:
- desc = '\n'.join((desc, doc_first_line))
- return desc
def id(self):
return "%s.%s" % (util.strclass(self.__class__), self._testMethodName)
@@ -501,7 +498,6 @@ class TestCase(object):
assertNotEquals = assertNotEqual
assertAlmostEquals = assertAlmostEqual
assertNotAlmostEquals = assertNotAlmostEqual
- assert_ = assertTrue
# These fail* assertion method names are pending deprecation and will
# be a DeprecationWarning in 3.2; http://bugs.python.org/issue2578
@@ -518,6 +514,7 @@ class TestCase(object):
failUnlessAlmostEqual = _deprecate(assertAlmostEqual)
failIfAlmostEqual = _deprecate(assertNotAlmostEqual)
failUnless = _deprecate(assertTrue)
+ assert_ = _deprecate(assertTrue)
failUnlessRaises = _deprecate(assertRaises)
failIf = _deprecate(assertFalse)
diff --git a/Lib/unittest/result.py b/Lib/unittest/result.py
index 3e32eb0..4538304 100644
--- a/Lib/unittest/result.py
+++ b/Lib/unittest/result.py
@@ -27,7 +27,7 @@ class TestResult(object):
def startTest(self, test):
"Called when the given test is about to be run"
- self.testsRun = self.testsRun + 1
+ self.testsRun += 1
def startTestRun(self):
"""Called once before any tests are executed.
@@ -36,8 +36,7 @@ class TestResult(object):
"""
def stopTest(self, test):
- "Called when the given test has been run"
- pass
+ """Called when the given test has been run"""
def stopTestRun(self):
"""Called once after all tests are executed.
diff --git a/Lib/unittest/runner.py b/Lib/unittest/runner.py
index 3ed9447..3f45f73 100644
--- a/Lib/unittest/runner.py
+++ b/Lib/unittest/runner.py
@@ -22,7 +22,7 @@ class _WritelnDecorator(object):
self.write('\n') # text-mode streams translate to \r\n if needed
-class _TextTestResult(result.TestResult):
+class TextTestResult(result.TestResult):
"""A test result class that can print formatted text results to a stream.
Used by TextTestRunner.
@@ -31,27 +31,28 @@ class _TextTestResult(result.TestResult):
separator2 = '-' * 70
def __init__(self, stream, descriptions, verbosity):
- super(_TextTestResult, self).__init__()
+ super(TextTestResult, self).__init__()
self.stream = stream
self.showAll = verbosity > 1
self.dots = verbosity == 1
self.descriptions = descriptions
def getDescription(self, test):
- if self.descriptions:
- return test.shortDescription() or str(test)
+ doc_first_line = test.shortDescription()
+ if self.descriptions and doc_first_line:
+ return '\n'.join((str(test), doc_first_line))
else:
return str(test)
def startTest(self, test):
- super(_TextTestResult, self).startTest(test)
+ super(TextTestResult, self).startTest(test)
if self.showAll:
self.stream.write(self.getDescription(test))
self.stream.write(" ... ")
self.stream.flush()
def addSuccess(self, test):
- super(_TextTestResult, self).addSuccess(test)
+ super(TextTestResult, self).addSuccess(test)
if self.showAll:
self.stream.writeln("ok")
elif self.dots:
@@ -59,7 +60,7 @@ class _TextTestResult(result.TestResult):
self.stream.flush()
def addError(self, test, err):
- super(_TextTestResult, self).addError(test, err)
+ super(TextTestResult, self).addError(test, err)
if self.showAll:
self.stream.writeln("ERROR")
elif self.dots:
@@ -67,7 +68,7 @@ class _TextTestResult(result.TestResult):
self.stream.flush()
def addFailure(self, test, err):
- super(_TextTestResult, self).addFailure(test, err)
+ super(TextTestResult, self).addFailure(test, err)
if self.showAll:
self.stream.writeln("FAIL")
elif self.dots:
@@ -75,7 +76,7 @@ class _TextTestResult(result.TestResult):
self.stream.flush()
def addSkip(self, test, reason):
- super(_TextTestResult, self).addSkip(test, reason)
+ super(TextTestResult, self).addSkip(test, reason)
if self.showAll:
self.stream.writeln("skipped {0!r}".format(reason))
elif self.dots:
@@ -83,7 +84,7 @@ class _TextTestResult(result.TestResult):
self.stream.flush()
def addExpectedFailure(self, test, err):
- super(_TextTestResult, self).addExpectedFailure(test, err)
+ super(TextTestResult, self).addExpectedFailure(test, err)
if self.showAll:
self.stream.writeln("expected failure")
elif self.dots:
@@ -91,7 +92,7 @@ class _TextTestResult(result.TestResult):
self.stream.flush()
def addUnexpectedSuccess(self, test):
- super(_TextTestResult, self).addUnexpectedSuccess(test)
+ super(TextTestResult, self).addUnexpectedSuccess(test)
if self.showAll:
self.stream.writeln("unexpected success")
elif self.dots:
@@ -118,13 +119,18 @@ class TextTestRunner(object):
It prints out the names of tests as they are run, errors as they
occur, and a summary of the results at the end of the test run.
"""
- def __init__(self, stream=sys.stderr, descriptions=1, verbosity=1):
+ resultclass = TextTestResult
+
+ def __init__(self, stream=sys.stderr, descriptions=True, verbosity=1,
+ resultclass=None):
self.stream = _WritelnDecorator(stream)
self.descriptions = descriptions
self.verbosity = verbosity
+ if resultclass is not None:
+ self.resultclass = resultclass
def _makeResult(self):
- return _TextTestResult(self.stream, self.descriptions, self.verbosity)
+ return self.resultclass(self.stream, self.descriptions, self.verbosity)
def run(self, test):
"Run the given test case or test suite."
diff --git a/Misc/NEWS b/Misc/NEWS
index e544868..cb489dd 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -447,6 +447,13 @@ Library
unpickled. This fixes crashes under Windows when trying to run
test_multiprocessing in verbose mode.
+- Issue #7893: ``unittest.TextTestResult`` is made public and a ``resultclass``
+ argument added to the TextTestRunner constructor allowing a different result
+ class to be used without having to subclass.
+
+- Issue 7588: ``unittest.TextTestResult.getDescription`` now includes the test
+ name in failure reports even if the test has a docstring.
+
- Issue #3001: Add a C implementation of recursive locks which is used by
default when instantiating a `threading.RLock` object. This makes
recursive locks as fast as regular non-recursive locks (previously,