Skip to content

Commit 7d4d02e

Browse files
andrewleechpi-anl
authored andcommitted
unittest: Log failure tracebacks at test end.
Store traceback details for each test failure and log to console at the end of the test, like CPython version of the module does.
1 parent a9cd99c commit 7d4d02e

File tree

1 file changed

+27
-4
lines changed

1 file changed

+27
-4
lines changed

python-stdlib/unittest/unittest.py

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
import sys
22

3+
try:
4+
import io
5+
import traceback
6+
except ImportError:
7+
import uio as io
8+
9+
traceback = None
10+
311

412
class SkipTest(Exception):
513
pass
@@ -160,7 +168,7 @@ class TestRunner:
160168
def run(self, suite):
161169
res = TestResult()
162170
for c in suite.tests:
163-
run_class(c, res)
171+
res.exceptions.extend(run_class(c, res))
164172

165173
print("Ran %d tests\n" % res.testsRun)
166174
if res.failuresNum > 0 or res.errorsNum > 0:
@@ -180,16 +188,27 @@ def __init__(self):
180188
self.failuresNum = 0
181189
self.skippedNum = 0
182190
self.testsRun = 0
191+
self.exceptions = []
183192

184193
def wasSuccessful(self):
185194
return self.errorsNum == 0 and self.failuresNum == 0
186195

187196

197+
def capture_exc(e):
198+
buf = io.StringIO()
199+
if hasattr(sys, "print_exception"):
200+
sys.print_exception(e, buf)
201+
elif traceback is not None:
202+
traceback.print_exception(None, e, sys.exc_info()[2], file=buf)
203+
return buf.getvalue()
204+
205+
188206
# TODO: Uncompliant
189207
def run_class(c, test_result):
190208
o = c()
191209
set_up = getattr(o, "setUp", lambda: None)
192210
tear_down = getattr(o, "tearDown", lambda: None)
211+
exceptions = []
193212
for name in dir(o):
194213
if name.startswith("test"):
195214
print("%s (%s) ..." % (name, c.__qualname__), end="")
@@ -202,14 +221,14 @@ def run_class(c, test_result):
202221
except SkipTest as e:
203222
print(" skipped:", e.args[0])
204223
test_result.skippedNum += 1
205-
except:
224+
except Exception as ex:
225+
exceptions.append(capture_exc(ex))
206226
print(" FAIL")
207227
test_result.failuresNum += 1
208-
# Uncomment to investigate failure in detail
209-
# raise
210228
continue
211229
finally:
212230
tear_down()
231+
return exceptions
213232

214233

215234
def main(module="__main__"):
@@ -225,5 +244,9 @@ def test_cases(m):
225244
suite.addTest(c)
226245
runner = TestRunner()
227246
result = runner.run(suite)
247+
if result.exceptions:
248+
sep = "\n----------------------------------------------------------------------\n"
249+
print(sep)
250+
print(sep.join(result.exceptions))
228251
# Terminate with non zero return code in case of failures
229252
sys.exit(result.failuresNum > 0)

0 commit comments

Comments
 (0)