From 6f5ea0dccd901150db9e077d7b5bb456200aea38 Mon Sep 17 00:00:00 2001 From: Olivier Guilyardi Date: Fri, 19 Feb 2010 17:40:36 +0000 Subject: [PATCH] add custom unittest runner (grouping by test cases) and a custom base TestCase --- tests/__init__.py | 140 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/tests/__init__.py b/tests/__init__.py index e69de29..2a6b9db 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -0,0 +1,140 @@ + +import unittest +import sys +import time + +class TestCase(unittest.TestCase): + + def assertSameList(self, list1, list2): + "Test that two lists contain the same elements, in any order" + if len(list1) != len(list2): + self.fail("Lists length differ : %d != %d" % (len(list1), len(list2))) + + for item in list1: + if not item in list2: + self.fail("%s is not in list2" % str(item)) + + for item in list2: + if not item in list1: + self.fail("%s is not in list1" % str(item)) + +class _TextTestResult(unittest.TestResult): + """A test result class that can print formatted text results to a stream. + + Used by TextTestRunner. + """ + separator1 = '=' * 70 + separator2 = '-' * 70 + + def __init__(self, stream, descriptions, verbosity): + unittest.TestResult.__init__(self) + self.stream = stream + self.showAll = verbosity > 1 + self.dots = verbosity == 1 + self.descriptions = descriptions + self.currentTestCase = None + + def getDescription(self, test): + if self.descriptions: + return test.shortDescription() or str(test) + else: + return str(test) + + def startTest(self, test): + unittest.TestResult.startTest(self, test) + if self.showAll: + if self.currentTestCase != test.__class__: + self.currentTestCase = test.__class__ + self.stream.writeln() + self.stream.writeln("[%s]" % self.currentTestCase.__name__) + self.stream.write(" " + self.getDescription(test)) + self.stream.write(" ... ") + + def addSuccess(self, test): + unittest.TestResult.addSuccess(self, test) + if self.showAll: + self.stream.writeln("ok") + elif self.dots: + self.stream.write('.') + + def addError(self, test, err): + unittest.TestResult.addError(self, test, err) + if self.showAll: + self.stream.writeln("ERROR") + elif self.dots: + self.stream.write('E') + + def addFailure(self, test, err): + unittest.TestResult.addFailure(self, test, err) + if self.showAll: + self.stream.writeln("FAIL") + elif self.dots: + self.stream.write('F') + + def printErrors(self): + if self.dots or self.showAll: + self.stream.writeln() + self.printErrorList('ERROR', self.errors) + self.printErrorList('FAIL', self.failures) + + def printErrorList(self, flavour, errors): + for test, err in errors: + self.stream.writeln(self.separator1) + self.stream.writeln("%s: %s" % (flavour,self.getDescription(test))) + self.stream.writeln(self.separator2) + self.stream.writeln("%s" % err) + + +class _WritelnDecorator: + """Used to decorate file-like objects with a handy 'writeln' method""" + def __init__(self,stream): + self.stream = stream + + def __getattr__(self, attr): + return getattr(self.stream,attr) + + def writeln(self, arg=None): + if arg: self.write(arg) + self.write('\n') # text-mode streams translate to \r\n if needed + +class TestRunner: + """A test runner class that displays results in textual form. + + 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=2): + self.stream = _WritelnDecorator(stream) + self.descriptions = descriptions + self.verbosity = verbosity + + def _makeResult(self): + return _TextTestResult(self.stream, self.descriptions, self.verbosity) + + def run(self, test): + "Run the given test case or test suite." + result = self._makeResult() + startTime = time.time() + test(result) + stopTime = time.time() + timeTaken = stopTime - startTime + result.printErrors() + self.stream.writeln(result.separator2) + run = result.testsRun + self.stream.writeln("Ran %d test%s in %.3fs" % + (run, run != 1 and "s" or "", timeTaken)) + self.stream.writeln() + if not result.wasSuccessful(): + self.stream.write("FAILED (") + failed, errored = map(len, (result.failures, result.errors)) + if failed: + self.stream.write("failures=%d" % failed) + if errored: + if failed: self.stream.write(", ") + self.stream.write("errors=%d" % errored) + self.stream.writeln(")") + else: + self.stream.writeln("OK") + return result + + -- 2.39.5