mirror of https://github.com/python/cpython
Issue #22936: Allow showing local variables in unittest errors.
This commit is contained in:
parent
e37a1946c7
commit
f0c819acd0
|
@ -223,9 +223,16 @@ Command-line options
|
||||||
|
|
||||||
Stop the test run on the first error or failure.
|
Stop the test run on the first error or failure.
|
||||||
|
|
||||||
|
.. cmdoption:: --locals
|
||||||
|
|
||||||
|
Show local variables in tracebacks.
|
||||||
|
|
||||||
.. versionadded:: 3.2
|
.. versionadded:: 3.2
|
||||||
The command-line options ``-b``, ``-c`` and ``-f`` were added.
|
The command-line options ``-b``, ``-c`` and ``-f`` were added.
|
||||||
|
|
||||||
|
.. versionadded:: 3.5
|
||||||
|
The command-line option ``--locals``.
|
||||||
|
|
||||||
The command line can also be used for test discovery, for running all of the
|
The command line can also be used for test discovery, for running all of the
|
||||||
tests in a project or just a subset.
|
tests in a project or just a subset.
|
||||||
|
|
||||||
|
@ -1782,12 +1789,10 @@ Loading and running tests
|
||||||
|
|
||||||
Set to ``True`` when the execution of tests should stop by :meth:`stop`.
|
Set to ``True`` when the execution of tests should stop by :meth:`stop`.
|
||||||
|
|
||||||
|
|
||||||
.. attribute:: testsRun
|
.. attribute:: testsRun
|
||||||
|
|
||||||
The total number of tests run so far.
|
The total number of tests run so far.
|
||||||
|
|
||||||
|
|
||||||
.. attribute:: buffer
|
.. attribute:: buffer
|
||||||
|
|
||||||
If set to true, ``sys.stdout`` and ``sys.stderr`` will be buffered in between
|
If set to true, ``sys.stdout`` and ``sys.stderr`` will be buffered in between
|
||||||
|
@ -1797,7 +1802,6 @@ Loading and running tests
|
||||||
|
|
||||||
.. versionadded:: 3.2
|
.. versionadded:: 3.2
|
||||||
|
|
||||||
|
|
||||||
.. attribute:: failfast
|
.. attribute:: failfast
|
||||||
|
|
||||||
If set to true :meth:`stop` will be called on the first failure or error,
|
If set to true :meth:`stop` will be called on the first failure or error,
|
||||||
|
@ -1805,6 +1809,11 @@ Loading and running tests
|
||||||
|
|
||||||
.. versionadded:: 3.2
|
.. versionadded:: 3.2
|
||||||
|
|
||||||
|
.. attribute:: tb_locals
|
||||||
|
|
||||||
|
If set to true then local variables will be shown in tracebacks.
|
||||||
|
|
||||||
|
.. versionadded:: 3.5
|
||||||
|
|
||||||
.. method:: wasSuccessful()
|
.. method:: wasSuccessful()
|
||||||
|
|
||||||
|
@ -1815,7 +1824,6 @@ Loading and running tests
|
||||||
Returns ``False`` if there were any :attr:`unexpectedSuccesses`
|
Returns ``False`` if there were any :attr:`unexpectedSuccesses`
|
||||||
from tests marked with the :func:`expectedFailure` decorator.
|
from tests marked with the :func:`expectedFailure` decorator.
|
||||||
|
|
||||||
|
|
||||||
.. method:: stop()
|
.. method:: stop()
|
||||||
|
|
||||||
This method can be called to signal that the set of tests being run should
|
This method can be called to signal that the set of tests being run should
|
||||||
|
@ -1947,12 +1955,14 @@ Loading and running tests
|
||||||
|
|
||||||
|
|
||||||
.. class:: TextTestRunner(stream=None, descriptions=True, verbosity=1, failfast=False, \
|
.. class:: TextTestRunner(stream=None, descriptions=True, verbosity=1, failfast=False, \
|
||||||
buffer=False, resultclass=None, warnings=None)
|
buffer=False, resultclass=None, warnings=None, *, tb_locals=False)
|
||||||
|
|
||||||
A basic test runner implementation that outputs results to a stream. If *stream*
|
A basic test runner implementation that outputs results to a stream. If *stream*
|
||||||
is ``None``, the default, :data:`sys.stderr` is used as the output stream. This class
|
is ``None``, the default, :data:`sys.stderr` is used as the output stream. This class
|
||||||
has a few configurable parameters, but is essentially very simple. Graphical
|
has a few configurable parameters, but is essentially very simple. Graphical
|
||||||
applications which run test suites should provide alternate implementations.
|
applications which run test suites should provide alternate implementations. Such
|
||||||
|
implementations should accept ``**kwargs`` as the interface to construct runners
|
||||||
|
changes when features are added to unittest.
|
||||||
|
|
||||||
By default this runner shows :exc:`DeprecationWarning`,
|
By default this runner shows :exc:`DeprecationWarning`,
|
||||||
:exc:`PendingDeprecationWarning`, :exc:`ResourceWarning` and
|
:exc:`PendingDeprecationWarning`, :exc:`ResourceWarning` and
|
||||||
|
@ -1971,6 +1981,9 @@ Loading and running tests
|
||||||
The default stream is set to :data:`sys.stderr` at instantiation time rather
|
The default stream is set to :data:`sys.stderr` at instantiation time rather
|
||||||
than import time.
|
than import time.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.5
|
||||||
|
Added the tb_locals parameter.
|
||||||
|
|
||||||
.. method:: _makeResult()
|
.. method:: _makeResult()
|
||||||
|
|
||||||
This method returns the instance of ``TestResult`` used by :meth:`run`.
|
This method returns the instance of ``TestResult`` used by :meth:`run`.
|
||||||
|
|
|
@ -58,7 +58,7 @@ class TestProgram(object):
|
||||||
def __init__(self, module='__main__', defaultTest=None, argv=None,
|
def __init__(self, module='__main__', defaultTest=None, argv=None,
|
||||||
testRunner=None, testLoader=loader.defaultTestLoader,
|
testRunner=None, testLoader=loader.defaultTestLoader,
|
||||||
exit=True, verbosity=1, failfast=None, catchbreak=None,
|
exit=True, verbosity=1, failfast=None, catchbreak=None,
|
||||||
buffer=None, warnings=None):
|
buffer=None, warnings=None, *, tb_locals=False):
|
||||||
if isinstance(module, str):
|
if isinstance(module, str):
|
||||||
self.module = __import__(module)
|
self.module = __import__(module)
|
||||||
for part in module.split('.')[1:]:
|
for part in module.split('.')[1:]:
|
||||||
|
@ -73,6 +73,7 @@ class TestProgram(object):
|
||||||
self.catchbreak = catchbreak
|
self.catchbreak = catchbreak
|
||||||
self.verbosity = verbosity
|
self.verbosity = verbosity
|
||||||
self.buffer = buffer
|
self.buffer = buffer
|
||||||
|
self.tb_locals = tb_locals
|
||||||
if warnings is None and not sys.warnoptions:
|
if warnings is None and not sys.warnoptions:
|
||||||
# even if DeprecationWarnings are ignored by default
|
# even if DeprecationWarnings are ignored by default
|
||||||
# print them anyway unless other warnings settings are
|
# print them anyway unless other warnings settings are
|
||||||
|
@ -159,7 +160,9 @@ class TestProgram(object):
|
||||||
parser.add_argument('-q', '--quiet', dest='verbosity',
|
parser.add_argument('-q', '--quiet', dest='verbosity',
|
||||||
action='store_const', const=0,
|
action='store_const', const=0,
|
||||||
help='Quiet output')
|
help='Quiet output')
|
||||||
|
parser.add_argument('--locals', dest='tb_locals',
|
||||||
|
action='store_true',
|
||||||
|
help='Show local variables in tracebacks')
|
||||||
if self.failfast is None:
|
if self.failfast is None:
|
||||||
parser.add_argument('-f', '--failfast', dest='failfast',
|
parser.add_argument('-f', '--failfast', dest='failfast',
|
||||||
action='store_true',
|
action='store_true',
|
||||||
|
@ -231,10 +234,18 @@ class TestProgram(object):
|
||||||
self.testRunner = runner.TextTestRunner
|
self.testRunner = runner.TextTestRunner
|
||||||
if isinstance(self.testRunner, type):
|
if isinstance(self.testRunner, type):
|
||||||
try:
|
try:
|
||||||
testRunner = self.testRunner(verbosity=self.verbosity,
|
try:
|
||||||
failfast=self.failfast,
|
testRunner = self.testRunner(verbosity=self.verbosity,
|
||||||
buffer=self.buffer,
|
failfast=self.failfast,
|
||||||
warnings=self.warnings)
|
buffer=self.buffer,
|
||||||
|
warnings=self.warnings,
|
||||||
|
tb_locals=self.tb_locals)
|
||||||
|
except TypeError:
|
||||||
|
# didn't accept the tb_locals argument
|
||||||
|
testRunner = self.testRunner(verbosity=self.verbosity,
|
||||||
|
failfast=self.failfast,
|
||||||
|
buffer=self.buffer,
|
||||||
|
warnings=self.warnings)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
# didn't accept the verbosity, buffer or failfast arguments
|
# didn't accept the verbosity, buffer or failfast arguments
|
||||||
testRunner = self.testRunner()
|
testRunner = self.testRunner()
|
||||||
|
|
|
@ -45,6 +45,7 @@ class TestResult(object):
|
||||||
self.unexpectedSuccesses = []
|
self.unexpectedSuccesses = []
|
||||||
self.shouldStop = False
|
self.shouldStop = False
|
||||||
self.buffer = False
|
self.buffer = False
|
||||||
|
self.tb_locals = False
|
||||||
self._stdout_buffer = None
|
self._stdout_buffer = None
|
||||||
self._stderr_buffer = None
|
self._stderr_buffer = None
|
||||||
self._original_stdout = sys.stdout
|
self._original_stdout = sys.stdout
|
||||||
|
@ -179,9 +180,11 @@ class TestResult(object):
|
||||||
if exctype is test.failureException:
|
if exctype is test.failureException:
|
||||||
# Skip assert*() traceback levels
|
# Skip assert*() traceback levels
|
||||||
length = self._count_relevant_tb_levels(tb)
|
length = self._count_relevant_tb_levels(tb)
|
||||||
msgLines = traceback.format_exception(exctype, value, tb, length)
|
|
||||||
else:
|
else:
|
||||||
msgLines = traceback.format_exception(exctype, value, tb)
|
length = None
|
||||||
|
tb_e = traceback.TracebackException(
|
||||||
|
exctype, value, tb, limit=length, capture_locals=self.tb_locals)
|
||||||
|
msgLines = list(tb_e.format())
|
||||||
|
|
||||||
if self.buffer:
|
if self.buffer:
|
||||||
output = sys.stdout.getvalue()
|
output = sys.stdout.getvalue()
|
||||||
|
|
|
@ -126,7 +126,13 @@ class TextTestRunner(object):
|
||||||
resultclass = TextTestResult
|
resultclass = TextTestResult
|
||||||
|
|
||||||
def __init__(self, stream=None, descriptions=True, verbosity=1,
|
def __init__(self, stream=None, descriptions=True, verbosity=1,
|
||||||
failfast=False, buffer=False, resultclass=None, warnings=None):
|
failfast=False, buffer=False, resultclass=None, warnings=None,
|
||||||
|
*, tb_locals=False):
|
||||||
|
"""Construct a TextTestRunner.
|
||||||
|
|
||||||
|
Subclasses should accept **kwargs to ensure compatibility as the
|
||||||
|
interface changes.
|
||||||
|
"""
|
||||||
if stream is None:
|
if stream is None:
|
||||||
stream = sys.stderr
|
stream = sys.stderr
|
||||||
self.stream = _WritelnDecorator(stream)
|
self.stream = _WritelnDecorator(stream)
|
||||||
|
@ -134,6 +140,7 @@ class TextTestRunner(object):
|
||||||
self.verbosity = verbosity
|
self.verbosity = verbosity
|
||||||
self.failfast = failfast
|
self.failfast = failfast
|
||||||
self.buffer = buffer
|
self.buffer = buffer
|
||||||
|
self.tb_locals = tb_locals
|
||||||
self.warnings = warnings
|
self.warnings = warnings
|
||||||
if resultclass is not None:
|
if resultclass is not None:
|
||||||
self.resultclass = resultclass
|
self.resultclass = resultclass
|
||||||
|
@ -147,6 +154,7 @@ class TextTestRunner(object):
|
||||||
registerResult(result)
|
registerResult(result)
|
||||||
result.failfast = self.failfast
|
result.failfast = self.failfast
|
||||||
result.buffer = self.buffer
|
result.buffer = self.buffer
|
||||||
|
result.tb_locals = self.tb_locals
|
||||||
with warnings.catch_warnings():
|
with warnings.catch_warnings():
|
||||||
if self.warnings:
|
if self.warnings:
|
||||||
# if self.warnings is set, use it to filter all the warnings
|
# if self.warnings is set, use it to filter all the warnings
|
||||||
|
|
|
@ -211,6 +211,7 @@ class TestBreak(unittest.TestCase):
|
||||||
self.verbosity = verbosity
|
self.verbosity = verbosity
|
||||||
self.failfast = failfast
|
self.failfast = failfast
|
||||||
self.catchbreak = catchbreak
|
self.catchbreak = catchbreak
|
||||||
|
self.tb_locals = False
|
||||||
self.testRunner = FakeRunner
|
self.testRunner = FakeRunner
|
||||||
self.test = test
|
self.test = test
|
||||||
self.result = None
|
self.result = None
|
||||||
|
@ -221,6 +222,7 @@ class TestBreak(unittest.TestCase):
|
||||||
self.assertEqual(FakeRunner.initArgs, [((), {'buffer': None,
|
self.assertEqual(FakeRunner.initArgs, [((), {'buffer': None,
|
||||||
'verbosity': verbosity,
|
'verbosity': verbosity,
|
||||||
'failfast': failfast,
|
'failfast': failfast,
|
||||||
|
'tb_locals': False,
|
||||||
'warnings': None})])
|
'warnings': None})])
|
||||||
self.assertEqual(FakeRunner.runArgs, [test])
|
self.assertEqual(FakeRunner.runArgs, [test])
|
||||||
self.assertEqual(p.result, result)
|
self.assertEqual(p.result, result)
|
||||||
|
@ -235,6 +237,7 @@ class TestBreak(unittest.TestCase):
|
||||||
self.assertEqual(FakeRunner.initArgs, [((), {'buffer': None,
|
self.assertEqual(FakeRunner.initArgs, [((), {'buffer': None,
|
||||||
'verbosity': verbosity,
|
'verbosity': verbosity,
|
||||||
'failfast': failfast,
|
'failfast': failfast,
|
||||||
|
'tb_locals': False,
|
||||||
'warnings': None})])
|
'warnings': None})])
|
||||||
self.assertEqual(FakeRunner.runArgs, [test])
|
self.assertEqual(FakeRunner.runArgs, [test])
|
||||||
self.assertEqual(p.result, result)
|
self.assertEqual(p.result, result)
|
||||||
|
|
|
@ -134,6 +134,7 @@ class InitialisableProgram(unittest.TestProgram):
|
||||||
result = None
|
result = None
|
||||||
verbosity = 1
|
verbosity = 1
|
||||||
defaultTest = None
|
defaultTest = None
|
||||||
|
tb_locals = False
|
||||||
testRunner = None
|
testRunner = None
|
||||||
testLoader = unittest.defaultTestLoader
|
testLoader = unittest.defaultTestLoader
|
||||||
module = '__main__'
|
module = '__main__'
|
||||||
|
@ -147,18 +148,19 @@ RESULT = object()
|
||||||
class FakeRunner(object):
|
class FakeRunner(object):
|
||||||
initArgs = None
|
initArgs = None
|
||||||
test = None
|
test = None
|
||||||
raiseError = False
|
raiseError = 0
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
FakeRunner.initArgs = kwargs
|
FakeRunner.initArgs = kwargs
|
||||||
if FakeRunner.raiseError:
|
if FakeRunner.raiseError:
|
||||||
FakeRunner.raiseError = False
|
FakeRunner.raiseError -= 1
|
||||||
raise TypeError
|
raise TypeError
|
||||||
|
|
||||||
def run(self, test):
|
def run(self, test):
|
||||||
FakeRunner.test = test
|
FakeRunner.test = test
|
||||||
return RESULT
|
return RESULT
|
||||||
|
|
||||||
|
|
||||||
class TestCommandLineArgs(unittest.TestCase):
|
class TestCommandLineArgs(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
@ -166,7 +168,7 @@ class TestCommandLineArgs(unittest.TestCase):
|
||||||
self.program.createTests = lambda: None
|
self.program.createTests = lambda: None
|
||||||
FakeRunner.initArgs = None
|
FakeRunner.initArgs = None
|
||||||
FakeRunner.test = None
|
FakeRunner.test = None
|
||||||
FakeRunner.raiseError = False
|
FakeRunner.raiseError = 0
|
||||||
|
|
||||||
def testVerbosity(self):
|
def testVerbosity(self):
|
||||||
program = self.program
|
program = self.program
|
||||||
|
@ -256,6 +258,7 @@ class TestCommandLineArgs(unittest.TestCase):
|
||||||
self.assertEqual(FakeRunner.initArgs, {'verbosity': 'verbosity',
|
self.assertEqual(FakeRunner.initArgs, {'verbosity': 'verbosity',
|
||||||
'failfast': 'failfast',
|
'failfast': 'failfast',
|
||||||
'buffer': 'buffer',
|
'buffer': 'buffer',
|
||||||
|
'tb_locals': False,
|
||||||
'warnings': 'warnings'})
|
'warnings': 'warnings'})
|
||||||
self.assertEqual(FakeRunner.test, 'test')
|
self.assertEqual(FakeRunner.test, 'test')
|
||||||
self.assertIs(program.result, RESULT)
|
self.assertIs(program.result, RESULT)
|
||||||
|
@ -274,10 +277,25 @@ class TestCommandLineArgs(unittest.TestCase):
|
||||||
self.assertEqual(FakeRunner.test, 'test')
|
self.assertEqual(FakeRunner.test, 'test')
|
||||||
self.assertIs(program.result, RESULT)
|
self.assertIs(program.result, RESULT)
|
||||||
|
|
||||||
|
def test_locals(self):
|
||||||
|
program = self.program
|
||||||
|
|
||||||
|
program.testRunner = FakeRunner
|
||||||
|
program.parseArgs([None, '--locals'])
|
||||||
|
self.assertEqual(True, program.tb_locals)
|
||||||
|
program.runTests()
|
||||||
|
self.assertEqual(FakeRunner.initArgs, {'buffer': False,
|
||||||
|
'failfast': False,
|
||||||
|
'tb_locals': True,
|
||||||
|
'verbosity': 1,
|
||||||
|
'warnings': None})
|
||||||
|
|
||||||
def testRunTestsOldRunnerClass(self):
|
def testRunTestsOldRunnerClass(self):
|
||||||
program = self.program
|
program = self.program
|
||||||
|
|
||||||
FakeRunner.raiseError = True
|
# Two TypeErrors are needed to fall all the way back to old-style
|
||||||
|
# runners - one to fail tb_locals, one to fail buffer etc.
|
||||||
|
FakeRunner.raiseError = 2
|
||||||
program.testRunner = FakeRunner
|
program.testRunner = FakeRunner
|
||||||
program.verbosity = 'verbosity'
|
program.verbosity = 'verbosity'
|
||||||
program.failfast = 'failfast'
|
program.failfast = 'failfast'
|
||||||
|
|
|
@ -8,6 +8,20 @@ import traceback
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
|
||||||
|
class MockTraceback(object):
|
||||||
|
class TracebackException:
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
self.capture_locals = kwargs.get('capture_locals', False)
|
||||||
|
def format(self):
|
||||||
|
result = ['A traceback']
|
||||||
|
if self.capture_locals:
|
||||||
|
result.append('locals')
|
||||||
|
return result
|
||||||
|
|
||||||
|
def restore_traceback():
|
||||||
|
unittest.result.traceback = traceback
|
||||||
|
|
||||||
|
|
||||||
class Test_TestResult(unittest.TestCase):
|
class Test_TestResult(unittest.TestCase):
|
||||||
# Note: there are not separate tests for TestResult.wasSuccessful(),
|
# Note: there are not separate tests for TestResult.wasSuccessful(),
|
||||||
# TestResult.errors, TestResult.failures, TestResult.testsRun or
|
# TestResult.errors, TestResult.failures, TestResult.testsRun or
|
||||||
|
@ -227,6 +241,25 @@ class Test_TestResult(unittest.TestCase):
|
||||||
self.assertIs(test_case, test)
|
self.assertIs(test_case, test)
|
||||||
self.assertIsInstance(formatted_exc, str)
|
self.assertIsInstance(formatted_exc, str)
|
||||||
|
|
||||||
|
def test_addError_locals(self):
|
||||||
|
class Foo(unittest.TestCase):
|
||||||
|
def test_1(self):
|
||||||
|
1/0
|
||||||
|
|
||||||
|
test = Foo('test_1')
|
||||||
|
result = unittest.TestResult()
|
||||||
|
result.tb_locals = True
|
||||||
|
|
||||||
|
unittest.result.traceback = MockTraceback
|
||||||
|
self.addCleanup(restore_traceback)
|
||||||
|
result.startTestRun()
|
||||||
|
test.run(result)
|
||||||
|
result.stopTestRun()
|
||||||
|
|
||||||
|
self.assertEqual(len(result.errors), 1)
|
||||||
|
test_case, formatted_exc = result.errors[0]
|
||||||
|
self.assertEqual('A tracebacklocals', formatted_exc)
|
||||||
|
|
||||||
def test_addSubTest(self):
|
def test_addSubTest(self):
|
||||||
class Foo(unittest.TestCase):
|
class Foo(unittest.TestCase):
|
||||||
def test_1(self):
|
def test_1(self):
|
||||||
|
@ -398,6 +431,7 @@ def __init__(self, stream=None, descriptions=None, verbosity=None):
|
||||||
self.testsRun = 0
|
self.testsRun = 0
|
||||||
self.shouldStop = False
|
self.shouldStop = False
|
||||||
self.buffer = False
|
self.buffer = False
|
||||||
|
self.tb_locals = False
|
||||||
|
|
||||||
classDict['__init__'] = __init__
|
classDict['__init__'] = __init__
|
||||||
OldResult = type('OldResult', (object,), classDict)
|
OldResult = type('OldResult', (object,), classDict)
|
||||||
|
@ -454,15 +488,6 @@ class Test_OldTestResult(unittest.TestCase):
|
||||||
runner.run(Test('testFoo'))
|
runner.run(Test('testFoo'))
|
||||||
|
|
||||||
|
|
||||||
class MockTraceback(object):
|
|
||||||
@staticmethod
|
|
||||||
def format_exception(*_):
|
|
||||||
return ['A traceback']
|
|
||||||
|
|
||||||
def restore_traceback():
|
|
||||||
unittest.result.traceback = traceback
|
|
||||||
|
|
||||||
|
|
||||||
class TestOutputBuffering(unittest.TestCase):
|
class TestOutputBuffering(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|
|
@ -158,7 +158,7 @@ class Test_TextTestRunner(unittest.TestCase):
|
||||||
self.assertEqual(runner.warnings, None)
|
self.assertEqual(runner.warnings, None)
|
||||||
self.assertTrue(runner.descriptions)
|
self.assertTrue(runner.descriptions)
|
||||||
self.assertEqual(runner.resultclass, unittest.TextTestResult)
|
self.assertEqual(runner.resultclass, unittest.TextTestResult)
|
||||||
|
self.assertFalse(runner.tb_locals)
|
||||||
|
|
||||||
def test_multiple_inheritance(self):
|
def test_multiple_inheritance(self):
|
||||||
class AResult(unittest.TestResult):
|
class AResult(unittest.TestResult):
|
||||||
|
@ -172,14 +172,13 @@ class Test_TextTestRunner(unittest.TestCase):
|
||||||
# on arguments in its __init__ super call
|
# on arguments in its __init__ super call
|
||||||
ATextResult(None, None, 1)
|
ATextResult(None, None, 1)
|
||||||
|
|
||||||
|
|
||||||
def testBufferAndFailfast(self):
|
def testBufferAndFailfast(self):
|
||||||
class Test(unittest.TestCase):
|
class Test(unittest.TestCase):
|
||||||
def testFoo(self):
|
def testFoo(self):
|
||||||
pass
|
pass
|
||||||
result = unittest.TestResult()
|
result = unittest.TestResult()
|
||||||
runner = unittest.TextTestRunner(stream=io.StringIO(), failfast=True,
|
runner = unittest.TextTestRunner(stream=io.StringIO(), failfast=True,
|
||||||
buffer=True)
|
buffer=True)
|
||||||
# Use our result object
|
# Use our result object
|
||||||
runner._makeResult = lambda: result
|
runner._makeResult = lambda: result
|
||||||
runner.run(Test('testFoo'))
|
runner.run(Test('testFoo'))
|
||||||
|
@ -187,6 +186,11 @@ class Test_TextTestRunner(unittest.TestCase):
|
||||||
self.assertTrue(result.failfast)
|
self.assertTrue(result.failfast)
|
||||||
self.assertTrue(result.buffer)
|
self.assertTrue(result.buffer)
|
||||||
|
|
||||||
|
def test_locals(self):
|
||||||
|
runner = unittest.TextTestRunner(stream=io.StringIO(), tb_locals=True)
|
||||||
|
result = runner.run(unittest.TestSuite())
|
||||||
|
self.assertEqual(True, result.tb_locals)
|
||||||
|
|
||||||
def testRunnerRegistersResult(self):
|
def testRunnerRegistersResult(self):
|
||||||
class Test(unittest.TestCase):
|
class Test(unittest.TestCase):
|
||||||
def testFoo(self):
|
def testFoo(self):
|
||||||
|
|
|
@ -39,7 +39,8 @@ Library
|
||||||
- Issue #21619: Popen objects no longer leave a zombie after exit in the with
|
- Issue #21619: Popen objects no longer leave a zombie after exit in the with
|
||||||
statement if the pipe was broken. Patch by Martin Panter.
|
statement if the pipe was broken. Patch by Martin Panter.
|
||||||
|
|
||||||
- Issue #22936: Make it possible to show local variables in tracebacks.
|
- Issue #22936: Make it possible to show local variables in tracebacks for
|
||||||
|
both the traceback module and unittest.
|
||||||
|
|
||||||
- Issue #15955: Add an option to limit the output size in bz2.decompress().
|
- Issue #15955: Add an option to limit the output size in bz2.decompress().
|
||||||
Patch by Nikolaus Rath.
|
Patch by Nikolaus Rath.
|
||||||
|
|
Loading…
Reference in New Issue