From ddeb9a7da2355bea917af99dbda6dc1d9926ba42 Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Tue, 3 May 2022 17:25:25 +1000 Subject: [PATCH] unittest: Improve failure text consistency with cpython. --- python-stdlib/unittest/unittest.py | 46 +++++++++++++++++++----------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/python-stdlib/unittest/unittest.py b/python-stdlib/unittest/unittest.py index 8d20acd7..0fcb3293 100644 --- a/python-stdlib/unittest/unittest.py +++ b/python-stdlib/unittest/unittest.py @@ -43,6 +43,10 @@ __test_result__ = None class SubtestContext: + def __init__(self, msg=None, params=None): + self.msg = msg + self.params = params + def __enter__(self): pass @@ -50,17 +54,18 @@ class SubtestContext: if exc_info[0] is not None: # Exception raised global __test_result__, __current_test__ - handle_test_exception( - __current_test__, - __test_result__, - exc_info - ) + test_details = __current_test__ + if self.msg: + test_details += (f" [{self.msg}]",) + if self.params: + detail = ", ".join(f"{k}={v}" for k, v in self.params.items()) + test_details += (f" ({detail})",) + + handle_test_exception(test_details, __test_result__, exc_info, False) # Suppress the exception as we've captured it above return True - - class NullContext: def __enter__(self): pass @@ -287,6 +292,7 @@ class TestResult: self.testsRun = 0 self.errors = [] self.failures = [] + self.newFailures = 0 def wasSuccessful(self): return self.errorsNum == 0 and self.failuresNum == 0 @@ -299,8 +305,9 @@ class TestResult: def printErrorList(self, lst): sep = "----------------------------------------------------------------------" for c, e in lst: + detail = " ".join((str(i) for i in c)) print("======================================================================") - print(c) + print(f"FAIL: {detail}") print(sep) print(e) @@ -331,18 +338,23 @@ def capture_exc(exc, traceback): return buf.getvalue() -def handle_test_exception(current_test: tuple, test_result: TestResult, exc_info: tuple): +def handle_test_exception( + current_test: tuple, test_result: TestResult, exc_info: tuple, verbose=True +): exc = exc_info[1] - traceback = exc_info[2] + traceback = exc_info[2] ex_str = capture_exc(exc, traceback) if isinstance(exc, AssertionError): test_result.failuresNum += 1 test_result.failures.append((current_test, ex_str)) - print(" FAIL") + if verbose: + print(" FAIL") else: test_result.errorsNum += 1 test_result.errors.append((current_test, ex_str)) - print(" ERROR") + if verbose: + print(" ERROR") + test_result.newFailures += 1 def run_suite(c, test_result, suite_name=""): @@ -370,20 +382,22 @@ def run_suite(c, test_result, suite_name=""): test_container = f"({suite_name})" __current_test__ = (name, test_container) try: + test_result.newFailures = 0 test_result.testsRun += 1 test_globals = dict(**globals()) test_globals["test_function"] = test_function exec("test_function()", test_globals, test_globals) # No exception occurred, test passed - print(" ok") + if test_result.newFailures: + print(" FAIL") + else: + print(" ok") except SkipTest as e: print(" skipped:", e.args[0]) test_result.skippedNum += 1 except Exception as ex: handle_test_exception( - current_test=(name, c), - test_result=test_result, - exc_info=sys.exc_info() + current_test=(name, c), test_result=test_result, exc_info=sys.exc_info() ) # Uncomment to investigate failure in detail # raise