Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f42a06b

Browse files
bpo-13236: Flush the output stream more often in unittest (GH-29864)
It can prevent some losses when output to buffered stream.
1 parent 87a18de commit f42a06b

File tree

4 files changed

+54
-5
lines changed

4 files changed

+54
-5
lines changed

Lib/unittest/runner.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ def _write_status(self, test, status):
6868
self.stream.write(self.getDescription(test))
6969
self.stream.write(" ... ")
7070
self.stream.writeln(status)
71+
self.stream.flush()
7172
self._newline = True
7273

7374
def addSubTest(self, test, subtest, err):
@@ -121,6 +122,7 @@ def addExpectedFailure(self, test, err):
121122
super(TextTestResult, self).addExpectedFailure(test, err)
122123
if self.showAll:
123124
self.stream.writeln("expected failure")
125+
self.stream.flush()
124126
elif self.dots:
125127
self.stream.write("x")
126128
self.stream.flush()
@@ -129,13 +131,15 @@ def addUnexpectedSuccess(self, test):
129131
super(TextTestResult, self).addUnexpectedSuccess(test)
130132
if self.showAll:
131133
self.stream.writeln("unexpected success")
134+
self.stream.flush()
132135
elif self.dots:
133136
self.stream.write("u")
134137
self.stream.flush()
135138

136139
def printErrors(self):
137140
if self.dots or self.showAll:
138141
self.stream.writeln()
142+
self.stream.flush()
139143
self.printErrorList('ERROR', self.errors)
140144
self.printErrorList('FAIL', self.failures)
141145

@@ -145,6 +149,7 @@ def printErrorList(self, flavour, errors):
145149
self.stream.writeln("%s: %s" % (flavour,self.getDescription(test)))
146150
self.stream.writeln(self.separator2)
147151
self.stream.writeln("%s" % err)
152+
self.stream.flush()
148153

149154

150155
class TextTestRunner(object):
@@ -239,4 +244,5 @@ def run(self, test):
239244
self.stream.writeln(" (%s)" % (", ".join(infos),))
240245
else:
241246
self.stream.write("\n")
247+
self.stream.flush()
242248
return result

Lib/unittest/test/test_program.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from test import support
77
import unittest
88
import unittest.test
9+
from .test_result import BufferedWriter
910

1011

1112
class Test_TestProgram(unittest.TestCase):
@@ -104,30 +105,39 @@ def run(self, test):
104105
program.testNames)
105106

106107
def test_NonExit(self):
108+
stream = BufferedWriter()
107109
program = unittest.main(exit=False,
108110
argv=["foobar"],
109-
testRunner=unittest.TextTestRunner(stream=io.StringIO()),
111+
testRunner=unittest.TextTestRunner(stream=stream),
110112
testLoader=self.FooBarLoader())
111113
self.assertTrue(hasattr(program, 'result'))
114+
self.assertIn('\nFAIL: testFail ', stream.getvalue())
115+
self.assertTrue(stream.getvalue().endswith('\n\nFAILED (failures=1)\n'))
112116

113117

114118
def test_Exit(self):
119+
stream = BufferedWriter()
115120
self.assertRaises(
116121
SystemExit,
117122
unittest.main,
118123
argv=["foobar"],
119-
testRunner=unittest.TextTestRunner(stream=io.StringIO()),
124+
testRunner=unittest.TextTestRunner(stream=stream),
120125
exit=True,
121126
testLoader=self.FooBarLoader())
127+
self.assertIn('\nFAIL: testFail ', stream.getvalue())
128+
self.assertTrue(stream.getvalue().endswith('\n\nFAILED (failures=1)\n'))
122129

123130

124131
def test_ExitAsDefault(self):
132+
stream = BufferedWriter()
125133
self.assertRaises(
126134
SystemExit,
127135
unittest.main,
128136
argv=["foobar"],
129-
testRunner=unittest.TextTestRunner(stream=io.StringIO()),
137+
testRunner=unittest.TextTestRunner(stream=stream),
130138
testLoader=self.FooBarLoader())
139+
self.assertIn('\nFAIL: testFail ', stream.getvalue())
140+
self.assertTrue(stream.getvalue().endswith('\n\nFAILED (failures=1)\n'))
131141

132142

133143
class InitialisableProgram(unittest.TestProgram):

Lib/unittest/test/test_result.py

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,22 @@ def bad_cleanup2():
3333
raise ValueError('bad cleanup2')
3434

3535

36+
class BufferedWriter:
37+
def __init__(self):
38+
self.result = ''
39+
self.buffer = ''
40+
41+
def write(self, arg):
42+
self.buffer += arg
43+
44+
def flush(self):
45+
self.result += self.buffer
46+
self.buffer = ''
47+
48+
def getvalue(self):
49+
return self.result
50+
51+
3652
class Test_TestResult(unittest.TestCase):
3753
# Note: there are not separate tests for TestResult.wasSuccessful(),
3854
# TestResult.errors, TestResult.failures, TestResult.testsRun or
@@ -335,10 +351,13 @@ def testFailFast(self):
335351
self.assertTrue(result.shouldStop)
336352

337353
def testFailFastSetByRunner(self):
338-
runner = unittest.TextTestRunner(stream=io.StringIO(), failfast=True)
354+
stream = BufferedWriter()
355+
runner = unittest.TextTestRunner(stream=stream, failfast=True)
339356
def test(result):
340357
self.assertTrue(result.failfast)
341358
result = runner.run(test)
359+
stream.flush()
360+
self.assertTrue(stream.getvalue().endswith('\n\nOK\n'))
342361

343362

344363
class Test_TextTestResult(unittest.TestCase):
@@ -462,6 +481,12 @@ def testFail(self):
462481
self.fail('fail')
463482
def testError(self):
464483
raise Exception('error')
484+
@unittest.expectedFailure
485+
def testExpectedFailure(self):
486+
self.fail('fail')
487+
@unittest.expectedFailure
488+
def testUnexpectedSuccess(self):
489+
pass
465490
def testSubTestSuccess(self):
466491
with self.subTest('one', a=1):
467492
pass
@@ -483,7 +508,7 @@ def tearDown(self):
483508
raise self.tearDownError
484509

485510
def _run_test(self, test_name, verbosity, tearDownError=None):
486-
stream = io.StringIO()
511+
stream = BufferedWriter()
487512
stream = unittest.runner._WritelnDecorator(stream)
488513
result = unittest.TextTestResult(stream, True, verbosity)
489514
test = self.Test(test_name)
@@ -496,6 +521,8 @@ def testDotsOutput(self):
496521
self.assertEqual(self._run_test('testSkip', 1), 's')
497522
self.assertEqual(self._run_test('testFail', 1), 'F')
498523
self.assertEqual(self._run_test('testError', 1), 'E')
524+
self.assertEqual(self._run_test('testExpectedFailure', 1), 'x')
525+
self.assertEqual(self._run_test('testUnexpectedSuccess', 1), 'u')
499526

500527
def testLongOutput(self):
501528
classname = f'{__name__}.{self.Test.__qualname__}'
@@ -507,6 +534,10 @@ def testLongOutput(self):
507534
f'testFail ({classname}) ... FAIL\n')
508535
self.assertEqual(self._run_test('testError', 2),
509536
f'testError ({classname}) ... ERROR\n')
537+
self.assertEqual(self._run_test('testExpectedFailure', 2),
538+
f'testExpectedFailure ({classname}) ... expected failure\n')
539+
self.assertEqual(self._run_test('testUnexpectedSuccess', 2),
540+
f'testUnexpectedSuccess ({classname}) ... unexpected success\n')
510541

511542
def testDotsOutputSubTestSuccess(self):
512543
self.assertEqual(self._run_test('testSubTestSuccess', 1), '.')
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
:class:`unittest.TextTestResult` and :class:`unittest.TextTestRunner` flush
2+
now the output stream more often.

0 commit comments

Comments
 (0)