0001 #!/usr/bin/env python 0002 ''' 0003 Python unit testing framework, based on Erich Gamma's JUnit and Kent Beck's 0004 Smalltalk testing framework. 0005 0006 This module contains the core framework classes that form the basis of 0007 specific test cases and suites (TestCase, TestSuite etc.), and also a 0008 text-based utility class for running the tests and reporting the results 0009 (TextTestRunner). 0010 0011 Simple usage: 0012 0013 import unittest 0014 0015 class IntegerArithmenticTestCase(unittest.TestCase): 0016 def testAdd(self): ## test method names begin 'test*' 0017 self.assertEquals((1 + 2), 3) 0018 self.assertEquals(0 + 1, 1) 0019 def testMultiply(self): 0020 self.assertEquals((0 * 10), 0) 0021 self.assertEquals((5 * 8), 40) 0022 0023 if __name__ == '__main__': 0024 unittest.main() 0025 0026 Further information is available in the bundled documentation, and from 0027 0028 http://pyunit.sourceforge.net/ 0029 0030 Copyright (c) 1999-2003 Steve Purcell 0031 This module is free software, and you may redistribute it and/or modify 0032 it under the same terms as Python itself, so long as this copyright message 0033 and disclaimer are retained in their original form. 0034 0035 IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, 0036 SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF 0037 THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 0038 DAMAGE. 0039 0040 THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT 0041 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 0042 PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, 0043 AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, 0044 SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 0045 ''' 0046 0047 __author__ = "Steve Purcell" 0048 __email__ = "stephen_purcell at yahoo dot com" 0049 __version__ = "#Revision: 1.63 $"[11:-2] 0050 0051 import time 0052 import sys 0053 import traceback 0054 import os 0055 import types 0056 0057 ############################################################################## 0058 # Exported classes and functions 0059 ############################################################################## 0060 __all__ = ['TestResult', 'TestCase', 'TestSuite', 'TextTestRunner', 0061 'TestLoader', 'FunctionTestCase', 'main', 'defaultTestLoader'] 0062 0063 # Expose obsolete functions for backwards compatibility 0064 __all__.extend(['getTestCaseNames', 'makeSuite', 'findTestCases']) 0065 0066 0067 ############################################################################## 0068 # Backward compatibility 0069 ############################################################################## 0070 if sys.version_info[:2] < (2, 2): 0071 False, True = 0, 1 0072 def isinstance(obj, clsinfo): 0073 import __builtin__ 0074 if type(clsinfo) in (types.TupleType, types.ListType): 0075 for cls in clsinfo: 0076 if cls is type: cls = types.ClassType 0077 if __builtin__.isinstance(obj, cls): 0078 return 1 0079 return 0 0080 else: return __builtin__.isinstance(obj, clsinfo) 0081 0082 0083 ############################################################################## 0084 # Test framework core 0085 ############################################################################## 0086 0087 # All classes defined herein are 'new-style' classes, allowing use of 'super()' 0088 __metaclass__ = type 0089 0090 def _strclass(cls): 0091 return "%s.%s" % (cls.__module__, cls.__name__) 0092 0093 __unittest = 1 0094 0095 class TestResult: 0096 """Holder for test result information. 0097 0098 Test results are automatically managed by the TestCase and TestSuite 0099 classes, and do not need to be explicitly manipulated by writers of tests. 0100 0101 Each instance holds the total number of tests run, and collections of 0102 failures and errors that occurred among those test runs. The collections 0103 contain tuples of (testcase, exceptioninfo), where exceptioninfo is the 0104 formatted traceback of the error that occurred. 0105 """ 0106 def __init__(self): 0107 self.failures = [] 0108 self.errors = [] 0109 self.testsRun = 0 0110 self.shouldStop = 0 0111 0112 def startTest(self, test): 0113 "Called when the given test is about to be run" 0114 self.testsRun = self.testsRun + 1 0115 0116 def stopTest(self, test): 0117 "Called when the given test has been run" 0118 pass 0119 0120 def addError(self, test, err): 0121 """Called when an error has occurred. 'err' is a tuple of values as 0122 returned by sys.exc_info(). 0123 """ 0124 self.errors.append((test, self._exc_info_to_string(err, test))) 0125 0126 def addFailure(self, test, err): 0127 """Called when an error has occurred. 'err' is a tuple of values as 0128 returned by sys.exc_info().""" 0129 self.failures.append((test, self._exc_info_to_string(err, test))) 0130 0131 def addSuccess(self, test): 0132 "Called when a test has completed successfully" 0133 pass 0134 0135 def wasSuccessful(self): 0136 "Tells whether or not this result was a success" 0137 return len(self.failures) == len(self.errors) == 0 0138 0139 def stop(self): 0140 "Indicates that the tests should be aborted" 0141 self.shouldStop = True 0142 0143 def _exc_info_to_string(self, err, test): 0144 """Converts a sys.exc_info()-style tuple of values into a string.""" 0145 exctype, value, tb = err 0146 # Skip test runner traceback levels 0147 while tb and self._is_relevant_tb_level(tb): 0148 tb = tb.tb_next 0149 if exctype is test.failureException: 0150 # Skip assert*() traceback levels 0151 length = self._count_relevant_tb_levels(tb) 0152 return ''.join(traceback.format_exception(exctype, value, tb, length)) 0153 return ''.join(traceback.format_exception(exctype, value, tb)) 0154 0155 def _is_relevant_tb_level(self, tb): 0156 return tb.tb_frame.f_globals.has_key('__unittest') 0157 0158 def _count_relevant_tb_levels(self, tb): 0159 length = 0 0160 while tb and not self._is_relevant_tb_level(tb): 0161 length += 1 0162 tb = tb.tb_next 0163 return length 0164 0165 def __repr__(self): 0166 return "<%s run=%i errors=%i failures=%i>" % \ 0167 (_strclass(self.__class__), self.testsRun, len(self.errors), 0168 len(self.failures)) 0169 0170 class TestCase: 0171 """A class whose instances are single test cases. 0172 0173 By default, the test code itself should be placed in a method named 0174 'runTest'. 0175 0176 If the fixture may be used for many test cases, create as 0177 many test methods as are needed. When instantiating such a TestCase 0178 subclass, specify in the constructor arguments the name of the test method 0179 that the instance is to execute. 0180 0181 Test authors should subclass TestCase for their own tests. Construction 0182 and deconstruction of the test's environment ('fixture') can be 0183 implemented by overriding the 'setUp' and 'tearDown' methods respectively. 0184 0185 If it is necessary to override the __init__ method, the base class 0186 __init__ method must always be called. It is important that subclasses 0187 should not change the signature of their __init__ method, since instances 0188 of the classes are instantiated automatically by parts of the framework 0189 in order to be run. 0190 """ 0191 0192 # This attribute determines which exception will be raised when 0193 # the instance's assertion methods fail; test methods raising this 0194 # exception will be deemed to have 'failed' rather than 'errored' 0195 0196 failureException = AssertionError 0197 0198 def __init__(self, methodName='runTest'): 0199 """Create an instance of the class that will use the named test 0200 method when executed. Raises a ValueError if the instance does 0201 not have a method with the specified name. 0202 """ 0203 try: 0204 self.__testMethodName = methodName 0205 testMethod = getattr(self, methodName) 0206 self.__testMethodDoc = testMethod.__doc__ 0207 except AttributeError: 0208 raise ValueError, "no such test method in %s: %s" % \ 0209 (self.__class__, methodName) 0210 0211 def setUp(self): 0212 "Hook method for setting up the test fixture before exercising it." 0213 pass 0214 0215 def tearDown(self): 0216 "Hook method for deconstructing the test fixture after testing it." 0217 pass 0218 0219 def countTestCases(self): 0220 return 1 0221 0222 def defaultTestResult(self): 0223 return TestResult() 0224 0225 def shortDescription(self): 0226 """Returns a one-line description of the test, or None if no 0227 description has been provided. 0228 0229 The default implementation of this method returns the first line of 0230 the specified test method's docstring. 0231 """ 0232 doc = self.__testMethodDoc 0233 return doc and doc.split("\n")[0].strip() or None 0234 0235 def id(self): 0236 return "%s.%s" % (_strclass(self.__class__), self.__testMethodName) 0237 0238 def __str__(self): 0239 return "%s (%s)" % (self.__testMethodName, _strclass(self.__class__)) 0240 0241 def __repr__(self): 0242 return "<%s testMethod=%s>" % \ 0243 (_strclass(self.__class__), self.__testMethodName) 0244 0245 def run(self, result=None): 0246 if result is None: result = self.defaultTestResult() 0247 result.startTest(self) 0248 testMethod = getattr(self, self.__testMethodName) 0249 try: 0250 try: 0251 self.setUp() 0252 except KeyboardInterrupt: 0253 raise 0254 except: 0255 result.addError(self, self.__exc_info()) 0256 return 0257 0258 ok = False 0259 try: 0260 testMethod() 0261 ok = True 0262 except self.failureException: 0263 result.addFailure(self, self.__exc_info()) 0264 except KeyboardInterrupt: 0265 raise 0266 except: 0267 result.addError(self, self.__exc_info()) 0268 0269 try: 0270 self.tearDown() 0271 except KeyboardInterrupt: 0272 raise 0273 except: 0274 result.addError(self, self.__exc_info()) 0275 ok = False 0276 if ok: result.addSuccess(self) 0277 finally: 0278 result.stopTest(self) 0279 0280 __call__ = run 0281 0282 def debug(self): 0283 """Run the test without collecting errors in a TestResult""" 0284 self.setUp() 0285 getattr(self, self.__testMethodName)() 0286 self.tearDown() 0287 0288 def __exc_info(self): 0289 """Return a version of sys.exc_info() with the traceback frame 0290 minimised; usually the top level of the traceback frame is not 0291 needed. 0292 """ 0293 exctype, excvalue, tb = sys.exc_info() 0294 if sys.platform[:4] == 'java': ## tracebacks look different in Jython 0295 return (exctype, excvalue, tb) 0296 return (exctype, excvalue, tb) 0297 0298 def fail(self, msg=None): 0299 """Fail immediately, with the given message.""" 0300 raise self.failureException, msg 0301 0302 def failIf(self, expr, msg=None): 0303 "Fail the test if the expression is true." 0304 if expr: raise self.failureException, msg 0305 0306 def failUnless(self, expr, msg=None): 0307 """Fail the test unless the expression is true.""" 0308 if not expr: raise self.failureException, msg 0309 0310 def failUnlessRaises(self, excClass, callableObj, *args, **kwargs): 0311 """Fail unless an exception of class excClass is thrown 0312 by callableObj when invoked with arguments args and keyword 0313 arguments kwargs. If a different type of exception is 0314 thrown, it will not be caught, and the test case will be 0315 deemed to have suffered an error, exactly as for an 0316 unexpected exception. 0317 """ 0318 try: 0319 callableObj(*args, **kwargs) 0320 except excClass: 0321 return 0322 else: 0323 if hasattr(excClass,'__name__'): excName = excClass.__name__ 0324 else: excName = str(excClass) 0325 raise self.failureException, "%s not raised" % excName 0326 0327 def failUnlessEqual(self, first, second, msg=None): 0328 """Fail if the two objects are unequal as determined by the '==' 0329 operator. 0330 """ 0331 if not first == second: 0332 raise self.failureException, \ 0333 (msg or '%r != %r' % (first, second)) 0334 0335 def failIfEqual(self, first, second, msg=None): 0336 """Fail if the two objects are equal as determined by the '==' 0337 operator. 0338 """ 0339 if first == second: 0340 raise self.failureException, \ 0341 (msg or '%r == %r' % (first, second)) 0342 0343 def failUnlessAlmostEqual(self, first, second, places=7, msg=None): 0344 """Fail if the two objects are unequal as determined by their 0345 difference rounded to the given number of decimal places 0346 (default 7) and comparing to zero. 0347 0348 Note that decimal places (from zero) are usually not the same 0349 as significant digits (measured from the most signficant digit). 0350 """ 0351 if round(second-first, places) != 0: 0352 raise self.failureException, \ 0353 (msg or '%r != %r within %r places' % (first, second, places)) 0354 0355 def failIfAlmostEqual(self, first, second, places=7, msg=None): 0356 """Fail if the two objects are equal as determined by their 0357 difference rounded to the given number of decimal places 0358 (default 7) and comparing to zero. 0359 0360 Note that decimal places (from zero) are usually not the same 0361 as significant digits (measured from the most signficant digit). 0362 """ 0363 if round(second-first, places) == 0: 0364 raise self.failureException, \ 0365 (msg or '%r == %r within %r places' % (first, second, places)) 0366 0367 # Synonyms for assertion methods 0368 0369 assertEqual = assertEquals = failUnlessEqual 0370 0371 assertNotEqual = assertNotEquals = failIfEqual 0372 0373 assertAlmostEqual = assertAlmostEquals = failUnlessAlmostEqual 0374 0375 assertNotAlmostEqual = assertNotAlmostEquals = failIfAlmostEqual 0376 0377 assertRaises = failUnlessRaises 0378 0379 assert_ = assertTrue = failUnless 0380 0381 assertFalse = failIf 0382 0383 0384 0385 class TestSuite: 0386 """A test suite is a composite test consisting of a number of TestCases. 0387 0388 For use, create an instance of TestSuite, then add test case instances. 0389 When all tests have been added, the suite can be passed to a test 0390 runner, such as TextTestRunner. It will run the individual test cases 0391 in the order in which they were added, aggregating the results. When 0392 subclassing, do not forget to call the base class constructor. 0393 """ 0394 def __init__(self, tests=()): 0395 self._tests = [] 0396 self.addTests(tests) 0397 0398 def __repr__(self): 0399 return "<%s tests=%s>" % (_strclass(self.__class__), self._tests) 0400 0401 __str__ = __repr__ 0402 0403 def __iter__(self): 0404 return iter(self._tests) 0405 0406 def countTestCases(self): 0407 cases = 0 0408 for test in self._tests: 0409 cases += test.countTestCases() 0410 return cases 0411 0412 def addTest(self, test): 0413 self._tests.append(test) 0414 0415 def addTests(self, tests): 0416 for test in tests: 0417 self.addTest(test) 0418 0419 def run(self, result): 0420 return self(result) 0421 0422 def __call__(self, result): 0423 for test in self._tests: 0424 if result.shouldStop: 0425 break 0426 test(result) 0427 return result 0428 0429 def debug(self): 0430 """Run the tests without collecting errors in a TestResult""" 0431 for test in self._tests: test.debug() 0432 0433 0434 class FunctionTestCase(TestCase): 0435 """A test case that wraps a test function. 0436 0437 This is useful for slipping pre-existing test functions into the 0438 PyUnit framework. Optionally, set-up and tidy-up functions can be 0439 supplied. As with TestCase, the tidy-up ('tearDown') function will 0440 always be called if the set-up ('setUp') function ran successfully. 0441 """ 0442 0443 def __init__(self, testFunc, setUp=None, tearDown=None, 0444 description=None): 0445 TestCase.__init__(self) 0446 self.__setUpFunc = setUp 0447 self.__tearDownFunc = tearDown 0448 self.__testFunc = testFunc 0449 self.__description = description 0450 0451 def setUp(self): 0452 if self.__setUpFunc is not None: 0453 self.__setUpFunc() 0454 0455 def tearDown(self): 0456 if self.__tearDownFunc is not None: 0457 self.__tearDownFunc() 0458 0459 def runTest(self): 0460 self.__testFunc() 0461 0462 def id(self): 0463 return self.__testFunc.__name__ 0464 0465 def __str__(self): 0466 return "%s (%s)" % (_strclass(self.__class__), self.__testFunc.__name__) 0467 0468 def __repr__(self): 0469 return "<%s testFunc=%s>" % (_strclass(self.__class__), self.__testFunc) 0470 0471 def shortDescription(self): 0472 if self.__description is not None: return self.__description 0473 doc = self.__testFunc.__doc__ 0474 return doc and doc.split("\n")[0].strip() or None 0475 0476 0477 0478 ############################################################################## 0479 # Locating and loading tests 0480 ############################################################################## 0481 0482 class TestLoader: 0483 """This class is responsible for loading tests according to various 0484 criteria and returning them wrapped in a Test 0485 """ 0486 testMethodPrefix = 'test' 0487 sortTestMethodsUsing = cmp 0488 suiteClass = TestSuite 0489 0490 def loadTestsFromTestCase(self, testCaseClass): 0491 """Return a suite of all tests cases contained in testCaseClass""" 0492 testCaseNames = self.getTestCaseNames(testCaseClass) 0493 if not testCaseNames and hasattr(testCaseClass, 'runTest'): 0494 testCaseNames = ['runTest'] 0495 return self.suiteClass(map(testCaseClass, testCaseNames)) 0496 0497 def loadTestsFromModule(self, module): 0498 """Return a suite of all tests cases contained in the given module""" 0499 tests = [] 0500 for name in dir(module): 0501 obj = getattr(module, name) 0502 if (isinstance(obj, (type, types.ClassType)) and 0503 issubclass(obj, TestCase)): 0504 tests.append(self.loadTestsFromTestCase(obj)) 0505 return self.suiteClass(tests) 0506 0507 def loadTestsFromName(self, name, module=None): 0508 """Return a suite of all tests cases given a string specifier. 0509 0510 The name may resolve either to a module, a test case class, a 0511 test method within a test case class, or a callable object which 0512 returns a TestCase or TestSuite instance. 0513 0514 The method optionally resolves the names relative to a given module. 0515 """ 0516 parts = name.split('.') 0517 if module is None: 0518 parts_copy = parts[:] 0519 while parts_copy: 0520 try: 0521 module = __import__('.'.join(parts_copy)) 0522 break 0523 except ImportError: 0524 del parts_copy[-1] 0525 if not parts_copy: raise 0526 parts = parts[1:] 0527 obj = module 0528 for part in parts: 0529 parent, obj = obj, getattr(obj, part) 0530 0531 if type(obj) == types.ModuleType: 0532 return self.loadTestsFromModule(obj) 0533 elif (isinstance(obj, (type, types.ClassType)) and 0534 issubclass(obj, TestCase)): 0535 return self.loadTestsFromTestCase(obj) 0536 elif type(obj) == types.UnboundMethodType: 0537 return parent(obj.__name__) 0538 elif isinstance(obj, TestSuite): 0539 return obj 0540 elif callable(obj): 0541 test = obj() 0542 if not isinstance(test, (TestCase, TestSuite)): 0543 raise ValueError, \ 0544 "calling %s returned %s, not a test" % (obj,test) 0545 return test 0546 else: 0547 raise ValueError, "don't know how to make test from: %s" % obj 0548 0549 def loadTestsFromNames(self, names, module=None): 0550 """Return a suite of all tests cases found using the given sequence 0551 of string specifiers. See 'loadTestsFromName()'. 0552 """ 0553 suites = [self.loadTestsFromName(name, module) for name in names] 0554 return self.suiteClass(suites) 0555 0556 def getTestCaseNames(self, testCaseClass): 0557 """Return a sorted sequence of method names found within testCaseClass 0558 """ 0559 def isTestMethod(attrname, testCaseClass=testCaseClass, prefix=self.testMethodPrefix): 0560 return attrname.startswith(prefix) and callable(getattr(testCaseClass, attrname)) 0561 testFnNames = filter(isTestMethod, dir(testCaseClass)) 0562 for baseclass in testCaseClass.__bases__: 0563 for testFnName in self.getTestCaseNames(baseclass): 0564 if testFnName not in testFnNames: # handle overridden methods 0565 testFnNames.append(testFnName) 0566 if self.sortTestMethodsUsing: 0567 testFnNames.sort(self.sortTestMethodsUsing) 0568 return testFnNames 0569 0570 0571 0572 defaultTestLoader = TestLoader() 0573 0574 0575 ############################################################################## 0576 # Patches for old functions: these functions should be considered obsolete 0577 ############################################################################## 0578 0579 def _makeLoader(prefix, sortUsing, suiteClass=None): 0580 loader = TestLoader() 0581 loader.sortTestMethodsUsing = sortUsing 0582 loader.testMethodPrefix = prefix 0583 if suiteClass: loader.suiteClass = suiteClass 0584 return loader 0585 0586 def getTestCaseNames(testCaseClass, prefix, sortUsing=cmp): 0587 return _makeLoader(prefix, sortUsing).getTestCaseNames(testCaseClass) 0588 0589 def makeSuite(testCaseClass, prefix='test', sortUsing=cmp, suiteClass=TestSuite): 0590 return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromTestCase(testCaseClass) 0591 0592 def findTestCases(module, prefix='test', sortUsing=cmp, suiteClass=TestSuite): 0593 return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromModule(module) 0594 0595 0596 ############################################################################## 0597 # Text UI 0598 ############################################################################## 0599 0600 class _WritelnDecorator: 0601 """Used to decorate file-like objects with a handy 'writeln' method""" 0602 def __init__(self,stream): 0603 self.stream = stream 0604 0605 def __getattr__(self, attr): 0606 return getattr(self.stream,attr) 0607 0608 def writeln(self, arg=None): 0609 if arg: self.write(arg) 0610 self.write('\n') # text-mode streams translate to \r\n if needed 0611 0612 0613 class _TextTestResult(TestResult): 0614 """A test result class that can print formatted text results to a stream. 0615 0616 Used by TextTestRunner. 0617 """ 0618 separator1 = '=' * 70 0619 separator2 = '-' * 70 0620 0621 def __init__(self, stream, descriptions, verbosity): 0622 TestResult.__init__(self) 0623 self.stream = stream 0624 self.showAll = verbosity > 1 0625 self.dots = verbosity == 1 0626 self.descriptions = descriptions 0627 0628 def getDescription(self, test): 0629 if self.descriptions: 0630 return test.shortDescription() or str(test) 0631 else: 0632 return str(test) 0633 0634 def startTest(self, test): 0635 TestResult.startTest(self, test) 0636 if self.showAll: 0637 self.stream.write(self.getDescription(test)) 0638 self.stream.write(" ... ") 0639 0640 def addSuccess(self, test): 0641 TestResult.addSuccess(self, test) 0642 if self.showAll: 0643 self.stream.writeln("ok") 0644 elif self.dots: 0645 self.stream.write('.') 0646 0647 def addError(self, test, err): 0648 TestResult.addError(self, test, err) 0649 if self.showAll: 0650 self.stream.writeln("ERROR") 0651 elif self.dots: 0652 self.stream.write('E') 0653 0654 def addFailure(self, test, err): 0655 TestResult.addFailure(self, test, err) 0656 if self.showAll: 0657 self.stream.writeln("FAIL") 0658 elif self.dots: 0659 self.stream.write('F') 0660 0661 def printErrors(self): 0662 if self.dots or self.showAll: 0663 self.stream.writeln() 0664 self.printErrorList('ERROR', self.errors) 0665 self.printErrorList('FAIL', self.failures) 0666 0667 def printErrorList(self, flavour, errors): 0668 for test, err in errors: 0669 self.stream.writeln(self.separator1) 0670 self.stream.writeln("%s: %s" % (flavour,self.getDescription(test))) 0671 self.stream.writeln(self.separator2) 0672 self.stream.writeln("%s" % err) 0673 0674 0675 class TextTestRunner: 0676 """A test runner class that displays results in textual form. 0677 0678 It prints out the names of tests as they are run, errors as they 0679 occur, and a summary of the results at the end of the test run. 0680 """ 0681 def __init__(self, stream=sys.stderr, descriptions=1, verbosity=1): 0682 self.stream = _WritelnDecorator(stream) 0683 self.descriptions = descriptions 0684 self.verbosity = verbosity 0685 0686 def _makeResult(self): 0687 return _TextTestResult(self.stream, self.descriptions, self.verbosity) 0688 0689 def run(self, test): 0690 "Run the given test case or test suite." 0691 result = self._makeResult() 0692 startTime = time.time() 0693 test(result) 0694 stopTime = time.time() 0695 timeTaken = stopTime - startTime 0696 result.printErrors() 0697 self.stream.writeln(result.separator2) 0698 run = result.testsRun 0699 self.stream.writeln("Ran %d test%s in %.3fs" % 0700 (run, run != 1 and "s" or "", timeTaken)) 0701 self.stream.writeln() 0702 if not result.wasSuccessful(): 0703 self.stream.write("FAILED (") 0704 failed, errored = map(len, (result.failures, result.errors)) 0705 if failed: 0706 self.stream.write("failures=%d" % failed) 0707 if errored: 0708 if failed: self.stream.write(", ") 0709 self.stream.write("errors=%d" % errored) 0710 self.stream.writeln(")") 0711 else: 0712 self.stream.writeln("OK") 0713 return result 0714 0715 0716 0717 ############################################################################## 0718 # Facilities for running tests from the command line 0719 ############################################################################## 0720 0721 class TestProgram: 0722 """A command-line program that runs a set of tests; this is primarily 0723 for making test modules conveniently executable. 0724 """ 0725 USAGE = """\ 0726 Usage: %(progName)s [options] [test] [...] 0727 0728 Options: 0729 -h, --help Show this message 0730 -v, --verbose Verbose output 0731 -q, --quiet Minimal output 0732 0733 Examples: 0734 %(progName)s - run default set of tests 0735 %(progName)s MyTestSuite - run suite 'MyTestSuite' 0736 %(progName)s MyTestCase.testSomething - run MyTestCase.testSomething 0737 %(progName)s MyTestCase - run all 'test*' test methods 0738 in MyTestCase 0739 """ 0740 def __init__(self, module='__main__', defaultTest=None, 0741 argv=None, testRunner=None, testLoader=defaultTestLoader): 0742 if type(module) == type(''): 0743 self.module = __import__(module) 0744 for part in module.split('.')[1:]: 0745 self.module = getattr(self.module, part) 0746 else: 0747 self.module = module 0748 if argv is None: 0749 argv = sys.argv 0750 self.verbosity = 1 0751 self.defaultTest = defaultTest 0752 self.testRunner = testRunner 0753 self.testLoader = testLoader 0754 self.progName = os.path.basename(argv[0]) 0755 self.parseArgs(argv) 0756 self.runTests() 0757 0758 def usageExit(self, msg=None): 0759 if msg: print msg 0760 print self.USAGE % self.__dict__ 0761 sys.exit(2) 0762 0763 def parseArgs(self, argv): 0764 import getopt 0765 try: 0766 options, args = getopt.getopt(argv[1:], 'hHvq', 0767 ['help','verbose','quiet']) 0768 for opt, value in options: 0769 if opt in ('-h','-H','--help'): 0770 self.usageExit() 0771 if opt in ('-q','--quiet'): 0772 self.verbosity = 0 0773 if opt in ('-v','--verbose'): 0774 self.verbosity = 2 0775 if len(args) == 0 and self.defaultTest is None: 0776 self.test = self.testLoader.loadTestsFromModule(self.module) 0777 return 0778 if len(args) > 0: 0779 self.testNames = args 0780 else: 0781 self.testNames = (self.defaultTest,) 0782 self.createTests() 0783 except getopt.error, msg: 0784 self.usageExit(msg) 0785 0786 def createTests(self): 0787 self.test = self.testLoader.loadTestsFromNames(self.testNames, 0788 self.module) 0789 0790 def runTests(self): 0791 if self.testRunner is None: 0792 self.testRunner = TextTestRunner(verbosity=self.verbosity) 0793 result = self.testRunner.run(self.test) 0794 sys.exit(not result.wasSuccessful()) 0795 0796 main = TestProgram 0797 0798 0799 ############################################################################## 0800 # Executing this module from the command line 0801 ############################################################################## 0802 0803 if __name__ == "__main__": 0804 main(module=None) 0805
Generated by PyXR 0.9.4