Module unittest
[hide private]
[frames] | no frames]

Source Code for Module unittest

  1  #! /usr/bin/python2.5 
  2  ''' 
  3  Python unit testing framework, based on Erich Gamma's JUnit and Kent Beck's 
  4  Smalltalk testing framework. 
  5   
  6  This module contains the core framework classes that form the basis of 
  7  specific test cases and suites (TestCase, TestSuite etc.), and also a 
  8  text-based utility class for running the tests and reporting the results 
  9   (TextTestRunner). 
 10   
 11  Simple usage: 
 12   
 13      import unittest 
 14   
 15      class IntegerArithmenticTestCase(unittest.TestCase): 
 16          def testAdd(self):  ## test method names begin 'test*' 
 17              self.assertEquals((1 + 2), 3) 
 18              self.assertEquals(0 + 1, 1) 
 19          def testMultiply(self): 
 20              self.assertEquals((0 * 10), 0) 
 21              self.assertEquals((5 * 8), 40) 
 22   
 23      if __name__ == '__main__': 
 24          unittest.main() 
 25   
 26  Further information is available in the bundled documentation, and from 
 27   
 28    http://pyunit.sourceforge.net/ 
 29   
 30  Copyright (c) 1999-2003 Steve Purcell 
 31  This module is free software, and you may redistribute it and/or modify 
 32  it under the same terms as Python itself, so long as this copyright message 
 33  and disclaimer are retained in their original form. 
 34   
 35  IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, 
 36  SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF 
 37  THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 
 38  DAMAGE. 
 39   
 40  THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT 
 41  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
 42  PARTICULAR PURPOSE.  THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, 
 43  AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, 
 44  SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 
 45  ''' 
 46   
 47  __author__ = "Steve Purcell" 
 48  __email__ = "stephen_purcell at yahoo dot com" 
 49  __version__ = "#Revision: 1.63 $"[11:-2] 
 50   
 51  import time 
 52  import sys 
 53  import traceback 
 54  import os 
 55  import types 
 56   
 57  ############################################################################## 
 58  # Exported classes and functions 
 59  ############################################################################## 
 60  __all__ = ['TestResult', 'TestCase', 'TestSuite', 'TextTestRunner', 
 61             'TestLoader', 'FunctionTestCase', 'main', 'defaultTestLoader'] 
 62   
 63  # Expose obsolete functions for backwards compatibility 
 64  __all__.extend(['getTestCaseNames', 'makeSuite', 'findTestCases']) 
 65   
 66   
 67  ############################################################################## 
 68  # Backward compatibility 
 69  ############################################################################## 
 70  if sys.version_info[:2] < (2, 2): 
 71      False, True = 0, 1 
72 - def isinstance(obj, clsinfo):
73 import __builtin__ 74 if type(clsinfo) in (tuple, list): 75 for cls in clsinfo: 76 if cls is type: cls = types.ClassType 77 if __builtin__.isinstance(obj, cls): 78 return 1 79 return 0 80 else: return __builtin__.isinstance(obj, clsinfo)
81 82 83 ############################################################################## 84 # Test framework core 85 ############################################################################## 86 87 # All classes defined herein are 'new-style' classes, allowing use of 'super()' 88 __metaclass__ = type 89
90 -def _strclass(cls):
91 return "%s.%s" % (cls.__module__, cls.__name__)
92 93 __unittest = 1 94
95 -class TestResult:
96 """Holder for test result information. 97 98 Test results are automatically managed by the TestCase and TestSuite 99 classes, and do not need to be explicitly manipulated by writers of tests. 100 101 Each instance holds the total number of tests run, and collections of 102 failures and errors that occurred among those test runs. The collections 103 contain tuples of (testcase, exceptioninfo), where exceptioninfo is the 104 formatted traceback of the error that occurred. 105 """
106 - def __init__(self):
107 self.failures = [] 108 self.errors = [] 109 self.testsRun = 0 110 self.shouldStop = 0
111
112 - def startTest(self, test):
113 "Called when the given test is about to be run" 114 self.testsRun = self.testsRun + 1
115
116 - def stopTest(self, test):
117 "Called when the given test has been run" 118 pass
119
120 - def addError(self, test, err):
121 """Called when an error has occurred. 'err' is a tuple of values as 122 returned by sys.exc_info(). 123 """ 124 self.errors.append((test, self._exc_info_to_string(err, test)))
125
126 - def addFailure(self, test, err):
127 """Called when an error has occurred. 'err' is a tuple of values as 128 returned by sys.exc_info().""" 129 self.failures.append((test, self._exc_info_to_string(err, test)))
130
131 - def addSuccess(self, test):
132 "Called when a test has completed successfully" 133 pass
134
135 - def wasSuccessful(self):
136 "Tells whether or not this result was a success" 137 return len(self.failures) == len(self.errors) == 0
138
139 - def stop(self):
140 "Indicates that the tests should be aborted" 141 self.shouldStop = True
142
143 - def _exc_info_to_string(self, err, test):
144 """Converts a sys.exc_info()-style tuple of values into a string.""" 145 exctype, value, tb = err 146 # Skip test runner traceback levels 147 while tb and self._is_relevant_tb_level(tb): 148 tb = tb.tb_next 149 if exctype is test.failureException: 150 # Skip assert*() traceback levels 151 length = self._count_relevant_tb_levels(tb) 152 return ''.join(traceback.format_exception(exctype, value, tb, length)) 153 return ''.join(traceback.format_exception(exctype, value, tb))
154
155 - def _is_relevant_tb_level(self, tb):
156 return tb.tb_frame.f_globals.has_key('__unittest')
157
158 - def _count_relevant_tb_levels(self, tb):
159 length = 0 160 while tb and not self._is_relevant_tb_level(tb): 161 length += 1 162 tb = tb.tb_next 163 return length
164
165 - def __repr__(self):
166 return "<%s run=%i errors=%i failures=%i>" % \ 167 (_strclass(self.__class__), self.testsRun, len(self.errors), 168 len(self.failures))
169
170 -class TestCase:
171 """A class whose instances are single test cases. 172 173 By default, the test code itself should be placed in a method named 174 'runTest'. 175 176 If the fixture may be used for many test cases, create as 177 many test methods as are needed. When instantiating such a TestCase 178 subclass, specify in the constructor arguments the name of the test method 179 that the instance is to execute. 180 181 Test authors should subclass TestCase for their own tests. Construction 182 and deconstruction of the test's environment ('fixture') can be 183 implemented by overriding the 'setUp' and 'tearDown' methods respectively. 184 185 If it is necessary to override the __init__ method, the base class 186 __init__ method must always be called. It is important that subclasses 187 should not change the signature of their __init__ method, since instances 188 of the classes are instantiated automatically by parts of the framework 189 in order to be run. 190 """ 191 192 # This attribute determines which exception will be raised when 193 # the instance's assertion methods fail; test methods raising this 194 # exception will be deemed to have 'failed' rather than 'errored' 195 196 failureException = AssertionError 197
198 - def __init__(self, methodName='runTest'):
199 """Create an instance of the class that will use the named test 200 method when executed. Raises a ValueError if the instance does 201 not have a method with the specified name. 202 """ 203 try: 204 self._testMethodName = methodName 205 testMethod = getattr(self, methodName) 206 self._testMethodDoc = testMethod.__doc__ 207 except AttributeError: 208 raise ValueError, "no such test method in %s: %s" % \ 209 (self.__class__, methodName)
210
211 - def setUp(self):
212 "Hook method for setting up the test fixture before exercising it." 213 pass
214
215 - def tearDown(self):
216 "Hook method for deconstructing the test fixture after testing it." 217 pass
218
219 - def countTestCases(self):
220 return 1
221
222 - def defaultTestResult(self):
223 return TestResult()
224
225 - def shortDescription(self):
226 """Returns a one-line description of the test, or None if no 227 description has been provided. 228 229 The default implementation of this method returns the first line of 230 the specified test method's docstring. 231 """ 232 doc = self._testMethodDoc 233 return doc and doc.split("\n")[0].strip() or None
234
235 - def id(self):
236 return "%s.%s" % (_strclass(self.__class__), self._testMethodName)
237
238 - def __str__(self):
239 return "%s (%s)" % (self._testMethodName, _strclass(self.__class__))
240
241 - def __repr__(self):
242 return "<%s testMethod=%s>" % \ 243 (_strclass(self.__class__), self._testMethodName)
244
245 - def run(self, result=None):
246 if result is None: result = self.defaultTestResult() 247 result.startTest(self) 248 testMethod = getattr(self, self._testMethodName) 249 try: 250 try: 251 self.setUp() 252 except KeyboardInterrupt: 253 raise 254 except: 255 result.addError(self, self._exc_info()) 256 return 257 258 ok = False 259 try: 260 testMethod() 261 ok = True 262 except self.failureException: 263 result.addFailure(self, self._exc_info()) 264 except KeyboardInterrupt: 265 raise 266 except: 267 result.addError(self, self._exc_info()) 268 269 try: 270 self.tearDown() 271 except KeyboardInterrupt: 272 raise 273 except: 274 result.addError(self, self._exc_info()) 275 ok = False 276 if ok: result.addSuccess(self) 277 finally: 278 result.stopTest(self)
279
280 - def __call__(self, *args, **kwds):
281 return self.run(*args, **kwds)
282
283 - def debug(self):
284 """Run the test without collecting errors in a TestResult""" 285 self.setUp() 286 getattr(self, self._testMethodName)() 287 self.tearDown()
288
289 - def _exc_info(self):
290 """Return a version of sys.exc_info() with the traceback frame 291 minimised; usually the top level of the traceback frame is not 292 needed. 293 """ 294 exctype, excvalue, tb = sys.exc_info() 295 if sys.platform[:4] == 'java': ## tracebacks look different in Jython 296 return (exctype, excvalue, tb) 297 return (exctype, excvalue, tb)
298
299 - def fail(self, msg=None):
300 """Fail immediately, with the given message.""" 301 raise self.failureException, msg
302
303 - def failIf(self, expr, msg=None):
304 "Fail the test if the expression is true." 305 if expr: raise self.failureException, msg
306
307 - def failUnless(self, expr, msg=None):
308 """Fail the test unless the expression is true.""" 309 if not expr: raise self.failureException, msg
310
311 - def failUnlessRaises(self, excClass, callableObj, *args, **kwargs):
312 """Fail unless an exception of class excClass is thrown 313 by callableObj when invoked with arguments args and keyword 314 arguments kwargs. If a different type of exception is 315 thrown, it will not be caught, and the test case will be 316 deemed to have suffered an error, exactly as for an 317 unexpected exception. 318 """ 319 try: 320 callableObj(*args, **kwargs) 321 except excClass: 322 return 323 else: 324 if hasattr(excClass,'__name__'): excName = excClass.__name__ 325 else: excName = str(excClass) 326 raise self.failureException, "%s not raised" % excName
327
328 - def failUnlessEqual(self, first, second, msg=None):
329 """Fail if the two objects are unequal as determined by the '==' 330 operator. 331 """ 332 if not first == second: 333 raise self.failureException, \ 334 (msg or '%r != %r' % (first, second))
335
336 - def failIfEqual(self, first, second, msg=None):
337 """Fail if the two objects are equal as determined by the '==' 338 operator. 339 """ 340 if first == second: 341 raise self.failureException, \ 342 (msg or '%r == %r' % (first, second))
343
344 - def failUnlessAlmostEqual(self, first, second, places=7, msg=None):
345 """Fail if the two objects are unequal as determined by their 346 difference rounded to the given number of decimal places 347 (default 7) and comparing to zero. 348 349 Note that decimal places (from zero) are usually not the same 350 as significant digits (measured from the most signficant digit). 351 """ 352 if round(second-first, places) != 0: 353 raise self.failureException, \ 354 (msg or '%r != %r within %r places' % (first, second, places))
355
356 - def failIfAlmostEqual(self, first, second, places=7, msg=None):
357 """Fail if the two objects are equal as determined by their 358 difference rounded to the given number of decimal places 359 (default 7) and comparing to zero. 360 361 Note that decimal places (from zero) are usually not the same 362 as significant digits (measured from the most signficant digit). 363 """ 364 if round(second-first, places) == 0: 365 raise self.failureException, \ 366 (msg or '%r == %r within %r places' % (first, second, places))
367 368 # Synonyms for assertion methods 369 370 assertEqual = assertEquals = failUnlessEqual 371 372 assertNotEqual = assertNotEquals = failIfEqual 373 374 assertAlmostEqual = assertAlmostEquals = failUnlessAlmostEqual 375 376 assertNotAlmostEqual = assertNotAlmostEquals = failIfAlmostEqual 377 378 assertRaises = failUnlessRaises 379 380 assert_ = assertTrue = failUnless 381 382 assertFalse = failIf
383 384 385
386 -class TestSuite:
387 """A test suite is a composite test consisting of a number of TestCases. 388 389 For use, create an instance of TestSuite, then add test case instances. 390 When all tests have been added, the suite can be passed to a test 391 runner, such as TextTestRunner. It will run the individual test cases 392 in the order in which they were added, aggregating the results. When 393 subclassing, do not forget to call the base class constructor. 394 """
395 - def __init__(self, tests=()):
396 self._tests = [] 397 self.addTests(tests)
398
399 - def __repr__(self):
400 return "<%s tests=%s>" % (_strclass(self.__class__), self._tests)
401 402 __str__ = __repr__ 403
404 - def __iter__(self):
405 return iter(self._tests)
406
407 - def countTestCases(self):
408 cases = 0 409 for test in self._tests: 410 cases += test.countTestCases() 411 return cases
412
413 - def addTest(self, test):
414 # sanity checks 415 if not callable(test): 416 raise TypeError("the test to add must be callable") 417 if (isinstance(test, (type, types.ClassType)) and 418 issubclass(test, (TestCase, TestSuite))): 419 raise TypeError("TestCases and TestSuites must be instantiated " 420 "before passing them to addTest()") 421 self._tests.append(test)
422
423 - def addTests(self, tests):
424 if isinstance(tests, basestring): 425 raise TypeError("tests must be an iterable of tests, not a string") 426 for test in tests: 427 self.addTest(test)
428
429 - def run(self, result):
430 for test in self._tests: 431 if result.shouldStop: 432 break 433 test(result) 434 return result
435
436 - def __call__(self, *args, **kwds):
437 return self.run(*args, **kwds)
438
439 - def debug(self):
440 """Run the tests without collecting errors in a TestResult""" 441 for test in self._tests: test.debug()
442 443
444 -class FunctionTestCase(TestCase):
445 """A test case that wraps a test function. 446 447 This is useful for slipping pre-existing test functions into the 448 PyUnit framework. Optionally, set-up and tidy-up functions can be 449 supplied. As with TestCase, the tidy-up ('tearDown') function will 450 always be called if the set-up ('setUp') function ran successfully. 451 """ 452
453 - def __init__(self, testFunc, setUp=None, tearDown=None, 454 description=None):
455 TestCase.__init__(self) 456 self.__setUpFunc = setUp 457 self.__tearDownFunc = tearDown 458 self.__testFunc = testFunc 459 self.__description = description
460
461 - def setUp(self):
462 if self.__setUpFunc is not None: 463 self.__setUpFunc()
464
465 - def tearDown(self):
466 if self.__tearDownFunc is not None: 467 self.__tearDownFunc()
468
469 - def runTest(self):
470 self.__testFunc()
471
472 - def id(self):
473 return self.__testFunc.__name__
474
475 - def __str__(self):
476 return "%s (%s)" % (_strclass(self.__class__), self.__testFunc.__name__)
477
478 - def __repr__(self):
479 return "<%s testFunc=%s>" % (_strclass(self.__class__), self.__testFunc)
480
481 - def shortDescription(self):
482 if self.__description is not None: return self.__description 483 doc = self.__testFunc.__doc__ 484 return doc and doc.split("\n")[0].strip() or None
485 486 487 488 ############################################################################## 489 # Locating and loading tests 490 ############################################################################## 491
492 -class TestLoader:
493 """This class is responsible for loading tests according to various 494 criteria and returning them wrapped in a Test 495 """ 496 testMethodPrefix = 'test' 497 sortTestMethodsUsing = cmp 498 suiteClass = TestSuite 499
500 - def loadTestsFromTestCase(self, testCaseClass):
501 """Return a suite of all tests cases contained in testCaseClass""" 502 if issubclass(testCaseClass, TestSuite): 503 raise TypeError("Test cases should not be derived from TestSuite. Maybe you meant to derive from TestCase?") 504 testCaseNames = self.getTestCaseNames(testCaseClass) 505 if not testCaseNames and hasattr(testCaseClass, 'runTest'): 506 testCaseNames = ['runTest'] 507 return self.suiteClass(map(testCaseClass, testCaseNames))
508
509 - def loadTestsFromModule(self, module):
510 """Return a suite of all tests cases contained in the given module""" 511 tests = [] 512 for name in dir(module): 513 obj = getattr(module, name) 514 if (isinstance(obj, (type, types.ClassType)) and 515 issubclass(obj, TestCase)): 516 tests.append(self.loadTestsFromTestCase(obj)) 517 return self.suiteClass(tests)
518
519 - def loadTestsFromName(self, name, module=None):
520 """Return a suite of all tests cases given a string specifier. 521 522 The name may resolve either to a module, a test case class, a 523 test method within a test case class, or a callable object which 524 returns a TestCase or TestSuite instance. 525 526 The method optionally resolves the names relative to a given module. 527 """ 528 parts = name.split('.') 529 if module is None: 530 parts_copy = parts[:] 531 while parts_copy: 532 try: 533 module = __import__('.'.join(parts_copy)) 534 break 535 except ImportError: 536 del parts_copy[-1] 537 if not parts_copy: raise 538 parts = parts[1:] 539 obj = module 540 for part in parts: 541 parent, obj = obj, getattr(obj, part) 542 543 if type(obj) == types.ModuleType: 544 return self.loadTestsFromModule(obj) 545 elif (isinstance(obj, (type, types.ClassType)) and 546 issubclass(obj, TestCase)): 547 return self.loadTestsFromTestCase(obj) 548 elif type(obj) == types.UnboundMethodType: 549 return parent(obj.__name__) 550 elif isinstance(obj, TestSuite): 551 return obj 552 elif callable(obj): 553 test = obj() 554 if not isinstance(test, (TestCase, TestSuite)): 555 raise ValueError, \ 556 "calling %s returned %s, not a test" % (obj,test) 557 return test 558 else: 559 raise ValueError, "don't know how to make test from: %s" % obj
560
561 - def loadTestsFromNames(self, names, module=None):
562 """Return a suite of all tests cases found using the given sequence 563 of string specifiers. See 'loadTestsFromName()'. 564 """ 565 suites = [self.loadTestsFromName(name, module) for name in names] 566 return self.suiteClass(suites)
567
568 - def getTestCaseNames(self, testCaseClass):
569 """Return a sorted sequence of method names found within testCaseClass 570 """ 571 def isTestMethod(attrname, testCaseClass=testCaseClass, prefix=self.testMethodPrefix): 572 return attrname.startswith(prefix) and callable(getattr(testCaseClass, attrname))
573 testFnNames = filter(isTestMethod, dir(testCaseClass)) 574 for baseclass in testCaseClass.__bases__: 575 for testFnName in self.getTestCaseNames(baseclass): 576 if testFnName not in testFnNames: # handle overridden methods 577 testFnNames.append(testFnName) 578 if self.sortTestMethodsUsing: 579 testFnNames.sort(self.sortTestMethodsUsing) 580 return testFnNames
581 582 583 584 defaultTestLoader = TestLoader() 585 586 587 ############################################################################## 588 # Patches for old functions: these functions should be considered obsolete 589 ############################################################################## 590
591 -def _makeLoader(prefix, sortUsing, suiteClass=None):
592 loader = TestLoader() 593 loader.sortTestMethodsUsing = sortUsing 594 loader.testMethodPrefix = prefix 595 if suiteClass: loader.suiteClass = suiteClass 596 return loader
597
598 -def getTestCaseNames(testCaseClass, prefix, sortUsing=cmp):
599 return _makeLoader(prefix, sortUsing).getTestCaseNames(testCaseClass)
600
601 -def makeSuite(testCaseClass, prefix='test', sortUsing=cmp, suiteClass=TestSuite):
602 return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromTestCase(testCaseClass)
603
604 -def findTestCases(module, prefix='test', sortUsing=cmp, suiteClass=TestSuite):
605 return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromModule(module)
606 607 608 ############################################################################## 609 # Text UI 610 ############################################################################## 611
612 -class _WritelnDecorator:
613 """Used to decorate file-like objects with a handy 'writeln' method"""
614 - def __init__(self,stream):
615 self.stream = stream
616
617 - def __getattr__(self, attr):
618 return getattr(self.stream,attr)
619
620 - def writeln(self, arg=None):
621 if arg: self.write(arg) 622 self.write('\n') # text-mode streams translate to \r\n if needed
623 624
625 -class _TextTestResult(TestResult):
626 """A test result class that can print formatted text results to a stream. 627 628 Used by TextTestRunner. 629 """ 630 separator1 = '=' * 70 631 separator2 = '-' * 70 632
633 - def __init__(self, stream, descriptions, verbosity):
634 TestResult.__init__(self) 635 self.stream = stream 636 self.showAll = verbosity > 1 637 self.dots = verbosity == 1 638 self.descriptions = descriptions
639
640 - def getDescription(self, test):
641 if self.descriptions: 642 return test.shortDescription() or str(test) 643 else: 644 return str(test)
645
646 - def startTest(self, test):
647 TestResult.startTest(self, test) 648 if self.showAll: 649 self.stream.write(self.getDescription(test)) 650 self.stream.write(" ... ")
651
652 - def addSuccess(self, test):
653 TestResult.addSuccess(self, test) 654 if self.showAll: 655 self.stream.writeln("ok") 656 elif self.dots: 657 self.stream.write('.')
658
659 - def addError(self, test, err):
660 TestResult.addError(self, test, err) 661 if self.showAll: 662 self.stream.writeln("ERROR") 663 elif self.dots: 664 self.stream.write('E')
665
666 - def addFailure(self, test, err):
667 TestResult.addFailure(self, test, err) 668 if self.showAll: 669 self.stream.writeln("FAIL") 670 elif self.dots: 671 self.stream.write('F')
672
673 - def printErrors(self):
674 if self.dots or self.showAll: 675 self.stream.writeln() 676 self.printErrorList('ERROR', self.errors) 677 self.printErrorList('FAIL', self.failures)
678
679 - def printErrorList(self, flavour, errors):
680 for test, err in errors: 681 self.stream.writeln(self.separator1) 682 self.stream.writeln("%s: %s" % (flavour,self.getDescription(test))) 683 self.stream.writeln(self.separator2) 684 self.stream.writeln("%s" % err)
685 686
687 -class TextTestRunner:
688 """A test runner class that displays results in textual form. 689 690 It prints out the names of tests as they are run, errors as they 691 occur, and a summary of the results at the end of the test run. 692 """
693 - def __init__(self, stream=sys.stderr, descriptions=1, verbosity=1):
694 self.stream = _WritelnDecorator(stream) 695 self.descriptions = descriptions 696 self.verbosity = verbosity
697
698 - def _makeResult(self):
699 return _TextTestResult(self.stream, self.descriptions, self.verbosity)
700
701 - def run(self, test):
702 "Run the given test case or test suite." 703 result = self._makeResult() 704 startTime = time.time() 705 test(result) 706 stopTime = time.time() 707 timeTaken = stopTime - startTime 708 result.printErrors() 709 self.stream.writeln(result.separator2) 710 run = result.testsRun 711 self.stream.writeln("Ran %d test%s in %.3fs" % 712 (run, run != 1 and "s" or "", timeTaken)) 713 self.stream.writeln() 714 if not result.wasSuccessful(): 715 self.stream.write("FAILED (") 716 failed, errored = map(len, (result.failures, result.errors)) 717 if failed: 718 self.stream.write("failures=%d" % failed) 719 if errored: 720 if failed: self.stream.write(", ") 721 self.stream.write("errors=%d" % errored) 722 self.stream.writeln(")") 723 else: 724 self.stream.writeln("OK") 725 return result
726 727 728 729 ############################################################################## 730 # Facilities for running tests from the command line 731 ############################################################################## 732
733 -class TestProgram:
734 """A command-line program that runs a set of tests; this is primarily 735 for making test modules conveniently executable. 736 """ 737 USAGE = """\ 738 Usage: %(progName)s [options] [test] [...] 739 740 Options: 741 -h, --help Show this message 742 -v, --verbose Verbose output 743 -q, --quiet Minimal output 744 745 Examples: 746 %(progName)s - run default set of tests 747 %(progName)s MyTestSuite - run suite 'MyTestSuite' 748 %(progName)s MyTestCase.testSomething - run MyTestCase.testSomething 749 %(progName)s MyTestCase - run all 'test*' test methods 750 in MyTestCase 751 """
752 - def __init__(self, module='__main__', defaultTest=None, 753 argv=None, testRunner=None, testLoader=defaultTestLoader):
754 if type(module) == type(''): 755 self.module = __import__(module) 756 for part in module.split('.')[1:]: 757 self.module = getattr(self.module, part) 758 else: 759 self.module = module 760 if argv is None: 761 argv = sys.argv 762 self.verbosity = 1 763 self.defaultTest = defaultTest 764 self.testRunner = testRunner 765 self.testLoader = testLoader 766 self.progName = os.path.basename(argv[0]) 767 self.parseArgs(argv) 768 self.runTests()
769
770 - def usageExit(self, msg=None):
771 if msg: print msg 772 print self.USAGE % self.__dict__ 773 sys.exit(2)
774
775 - def parseArgs(self, argv):
776 import getopt 777 try: 778 options, args = getopt.getopt(argv[1:], 'hHvq', 779 ['help','verbose','quiet']) 780 for opt, value in options: 781 if opt in ('-h','-H','--help'): 782 self.usageExit() 783 if opt in ('-q','--quiet'): 784 self.verbosity = 0 785 if opt in ('-v','--verbose'): 786 self.verbosity = 2 787 if len(args) == 0 and self.defaultTest is None: 788 self.test = self.testLoader.loadTestsFromModule(self.module) 789 return 790 if len(args) > 0: 791 self.testNames = args 792 else: 793 self.testNames = (self.defaultTest,) 794 self.createTests() 795 except getopt.error, msg: 796 self.usageExit(msg)
797
798 - def createTests(self):
799 self.test = self.testLoader.loadTestsFromNames(self.testNames, 800 self.module)
801
802 - def runTests(self):
803 if self.testRunner is None: 804 self.testRunner = TextTestRunner(verbosity=self.verbosity) 805 result = self.testRunner.run(self.test) 806 sys.exit(not result.wasSuccessful())
807 808 main = TestProgram 809 810 811 ############################################################################## 812 # Executing this module from the command line 813 ############################################################################## 814 815 if __name__ == "__main__": 816 main(module=None) 817