Use the same rounding for width as for height in platform sections -- covers ticket...
[pyTivo.git] / Cheetah / Tests / unittest_local_copy.py
blob54061ae6520d31831b578178b6eda6b3107c28d9
1 #!/usr/bin/env python
2 """ This is a hacked version of PyUnit that extends its reporting capabilities
3 with optional meta data on the test cases. It also makes it possible to
4 separate the standard and error output streams in TextTestRunner.
6 It's a hack rather than a set of subclasses because a) Steve had used double
7 underscore private attributes for some things I needed access to, and b) the
8 changes affected so many classes that it was easier just to hack it.
10 The changes are in the following places:
11 TestCase:
12 - minor refactoring of __init__ and __call__ internals
13 - added some attributes and methods for storing and retrieving meta data
15 _TextTestResult
16 - refactored the stream handling
17 - incorporated all the output code from TextTestRunner
18 - made the output of FAIL and ERROR information more flexible and
19 incorporated the new meta data from TestCase
20 - added a flag called 'explain' to __init__ that controls whether the new '
21 explanation' meta data from TestCase is printed along with tracebacks
23 TextTestRunner
24 - delegated all output to _TextTestResult
25 - added 'err' and 'explain' to the __init__ signature to match the changes
26 in _TextTestResult
28 TestProgram
29 - added -e and --explain as flags on the command line
31 -- Tavis Rudd <tavis@redonions.net> (Sept 28th, 2001)
33 - _TestTextResult.printErrorList(): print blank line after each traceback
35 -- Mike Orr <mso@oz.net> (Nov 11, 2002)
37 TestCase methods copied from unittest in Python 2.3:
38 - .assertAlmostEqual(first, second, places=7, msg=None): to N decimal places.
39 - .failIfAlmostEqual(first, second, places=7, msg=None)
41 -- Mike Orr (Jan 5, 2004)
44 Below is the original docstring for unittest.
45 ---------------------------------------------------------------------------
46 Python unit testing framework, based on Erich Gamma's JUnit and Kent Beck's
47 Smalltalk testing framework.
49 This module contains the core framework classes that form the basis of
50 specific test cases and suites (TestCase, TestSuite etc.), and also a
51 text-based utility class for running the tests and reporting the results
52 (TextTestRunner).
54 Simple usage:
56 import unittest
58 class IntegerArithmenticTestCase(unittest.TestCase):
59 def testAdd(self): ## test method names begin 'test*'
60 self.assertEquals((1 + 2), 3)
61 self.assertEquals(0 + 1, 1)
62 def testMultiply(self);
63 self.assertEquals((0 * 10), 0)
64 self.assertEquals((5 * 8), 40)
66 if __name__ == '__main__':
67 unittest.main()
69 Further information is available in the bundled documentation, and from
71 http://pyunit.sourceforge.net/
73 Copyright (c) 1999, 2000, 2001 Steve Purcell
74 This module is free software, and you may redistribute it and/or modify
75 it under the same terms as Python itself, so long as this copyright message
76 and disclaimer are retained in their original form.
78 IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
79 SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF
80 THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
81 DAMAGE.
83 THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
84 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
85 PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS,
86 AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
87 SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
88 """
90 __author__ = "Steve Purcell"
91 __email__ = "stephen_purcell at yahoo dot com"
92 __revision__ = "$Revision: 1.11 $"[11:-2]
95 ##################################################
96 ## DEPENDENCIES ##
98 import os
99 import re
100 import string
101 import sys
102 import time
103 import traceback
104 import types
105 import pprint
107 ##################################################
108 ## CONSTANTS & GLOBALS
110 try:
111 True,False
112 except NameError:
113 True, False = (1==1),(1==0)
115 ##############################################################################
116 # Test framework core
117 ##############################################################################
120 class TestResult:
121 """Holder for test result information.
123 Test results are automatically managed by the TestCase and TestSuite
124 classes, and do not need to be explicitly manipulated by writers of tests.
126 Each instance holds the total number of tests run, and collections of
127 failures and errors that occurred among those test runs. The collections
128 contain tuples of (testcase, exceptioninfo), where exceptioninfo is a
129 tuple of values as returned by sys.exc_info().
131 def __init__(self):
132 self.failures = []
133 self.errors = []
134 self.testsRun = 0
135 self.shouldStop = 0
137 def startTest(self, test):
138 "Called when the given test is about to be run"
139 self.testsRun = self.testsRun + 1
141 def stopTest(self, test):
142 "Called when the given test has been run"
143 pass
145 def addError(self, test, err):
146 "Called when an error has occurred"
147 self.errors.append((test, err))
149 def addFailure(self, test, err):
150 "Called when a failure has occurred"
151 self.failures.append((test, err))
153 def addSuccess(self, test):
154 "Called when a test has completed successfully"
155 pass
157 def wasSuccessful(self):
158 "Tells whether or not this result was a success"
159 return len(self.failures) == len(self.errors) == 0
161 def stop(self):
162 "Indicates that the tests should be aborted"
163 self.shouldStop = 1
165 def __repr__(self):
166 return "<%s run=%i errors=%i failures=%i>" % \
167 (self.__class__, self.testsRun, len(self.errors),
168 len(self.failures))
170 class TestCase:
171 """A class whose instances are single test cases.
173 By default, the test code itself should be placed in a method named
174 'runTest'.
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.
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.
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.
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'
196 failureException = AssertionError
198 # the name of the fixture. Used for displaying meta data about the test
199 name = None
201 def __init__(self, methodName='runTest'):
202 """Create an instance of the class that will use the named test
203 method when executed. Raises a ValueError if the instance does
204 not have a method with the specified name.
206 self._testMethodName = methodName
207 self._setupTestMethod()
208 self._setupMetaData()
210 def _setupTestMethod(self):
211 try:
212 self._testMethod = getattr(self, self._testMethodName)
213 except AttributeError:
214 raise ValueError, "no such test method in %s: %s" % \
215 (self.__class__, self._testMethodName)
217 ## meta data methods
219 def _setupMetaData(self):
220 """Setup the default meta data for the test case:
222 - id: self.__class__.__name__ + testMethodName OR self.name + testMethodName
223 - description: 1st line of Class docstring + 1st line of method docstring
224 - explanation: rest of Class docstring + rest of method docstring
229 testDoc = self._testMethod.__doc__ or '\n'
230 testDocLines = testDoc.splitlines()
232 testDescription = testDocLines[0].strip()
233 if len(testDocLines) > 1:
234 testExplanation = '\n'.join(
235 [ln.strip() for ln in testDocLines[1:]]
236 ).strip()
237 else:
238 testExplanation = ''
240 fixtureDoc = self.__doc__ or '\n'
241 fixtureDocLines = fixtureDoc.splitlines()
242 fixtureDescription = fixtureDocLines[0].strip()
243 if len(fixtureDocLines) > 1:
244 fixtureExplanation = '\n'.join(
245 [ln.strip() for ln in fixtureDocLines[1:]]
246 ).strip()
247 else:
248 fixtureExplanation = ''
250 if not self.name:
251 self.name = self.__class__
252 self._id = "%s.%s" % (self.name, self._testMethodName)
254 if not fixtureDescription:
255 self._description = testDescription
256 else:
257 self._description = fixtureDescription + ', ' + testDescription
259 if not fixtureExplanation:
260 self._explanation = testExplanation
261 else:
262 self._explanation = ['Fixture Explanation:',
263 '--------------------',
264 fixtureExplanation,
266 'Test Explanation:',
267 '-----------------',
268 testExplanation
270 self._explanation = '\n'.join(self._explanation)
272 def id(self):
273 return self._id
275 def setId(self, id):
276 self._id = id
278 def describe(self):
279 """Returns a one-line description of the test, or None if no
280 description has been provided.
282 The default implementation of this method returns the first line of
283 the specified test method's docstring.
285 return self._description
287 shortDescription = describe
289 def setDescription(self, descr):
290 self._description = descr
292 def explain(self):
293 return self._explanation
295 def setExplanation(self, expln):
296 self._explanation = expln
298 ## core methods
300 def setUp(self):
301 "Hook method for setting up the test fixture before exercising it."
302 pass
304 def run(self, result=None):
305 return self(result)
307 def tearDown(self):
308 "Hook method for deconstructing the test fixture after testing it."
309 pass
311 def debug(self):
312 """Run the test without collecting errors in a TestResult"""
313 self.setUp()
314 self._testMethod()
315 self.tearDown()
317 ## internal methods
319 def defaultTestResult(self):
320 return TestResult()
322 def __call__(self, result=None):
323 if result is None:
324 result = self.defaultTestResult()
326 result.startTest(self)
327 try:
328 try:
329 self.setUp()
330 except:
331 result.addError(self, self.__exc_info())
332 return
334 ok = 0
335 try:
336 self._testMethod()
337 ok = 1
338 except self.failureException, e:
339 result.addFailure(self, self.__exc_info())
340 except:
341 result.addError(self, self.__exc_info())
342 try:
343 self.tearDown()
344 except:
345 result.addError(self, self.__exc_info())
346 ok = 0
347 if ok:
348 result.addSuccess(self)
349 finally:
350 result.stopTest(self)
352 return result
354 def countTestCases(self):
355 return 1
357 def __str__(self):
358 return "%s (%s)" % (self._testMethodName, self.__class__)
360 def __repr__(self):
361 return "<%s testMethod=%s>" % \
362 (self.__class__, self._testMethodName)
364 def __exc_info(self):
365 """Return a version of sys.exc_info() with the traceback frame
366 minimised; usually the top level of the traceback frame is not
367 needed.
369 exctype, excvalue, tb = sys.exc_info()
370 if sys.platform[:4] == 'java': ## tracebacks look different in Jython
371 return (exctype, excvalue, tb)
372 newtb = tb.tb_next
373 if newtb is None:
374 return (exctype, excvalue, tb)
375 return (exctype, excvalue, newtb)
377 ## methods for use by the test cases
379 def fail(self, msg=None):
380 """Fail immediately, with the given message."""
381 raise self.failureException, msg
383 def failIf(self, expr, msg=None):
384 "Fail the test if the expression is true."
385 if expr: raise self.failureException, msg
387 def failUnless(self, expr, msg=None):
388 """Fail the test unless the expression is true."""
389 if not expr: raise self.failureException, msg
391 def failUnlessRaises(self, excClass, callableObj, *args, **kwargs):
392 """Fail unless an exception of class excClass is thrown
393 by callableObj when invoked with arguments args and keyword
394 arguments kwargs. If a different type of exception is
395 thrown, it will not be caught, and the test case will be
396 deemed to have suffered an error, exactly as for an
397 unexpected exception.
399 try:
400 apply(callableObj, args, kwargs)
401 except excClass:
402 return
403 else:
404 if hasattr(excClass,'__name__'): excName = excClass.__name__
405 else: excName = str(excClass)
406 raise self.failureException, excName
408 def failUnlessEqual(self, first, second, msg=None):
409 """Fail if the two objects are unequal as determined by the '!='
410 operator.
412 if first != second:
413 raise self.failureException, (msg or '%s != %s' % (first, second))
415 def failIfEqual(self, first, second, msg=None):
416 """Fail if the two objects are equal as determined by the '=='
417 operator.
419 if first == second:
420 raise self.failureException, (msg or '%s == %s' % (first, second))
422 def failUnlessAlmostEqual(self, first, second, places=7, msg=None):
423 """Fail if the two objects are unequal as determined by their
424 difference rounded to the given number of decimal places
425 (default 7) and comparing to zero.
427 Note that decimal places (from zero) is usually not the same
428 as significant digits (measured from the most signficant digit).
430 if round(second-first, places) != 0:
431 raise self.failureException, \
432 (msg or '%s != %s within %s places' % (`first`, `second`, `places` ))
434 def failIfAlmostEqual(self, first, second, places=7, msg=None):
435 """Fail if the two objects are equal as determined by their
436 difference rounded to the given number of decimal places
437 (default 7) and comparing to zero.
439 Note that decimal places (from zero) is usually not the same
440 as significant digits (measured from the most signficant digit).
442 if round(second-first, places) == 0:
443 raise self.failureException, \
444 (msg or '%s == %s within %s places' % (`first`, `second`, `places`))
446 ## aliases
448 assertEqual = assertEquals = failUnlessEqual
450 assertNotEqual = assertNotEquals = failIfEqual
452 assertAlmostEqual = assertAlmostEquals = failUnlessAlmostEqual
454 assertNotAlmostEqual = assertNotAlmostEquals = failIfAlmostEqual
456 assertRaises = failUnlessRaises
458 assert_ = failUnless
461 class FunctionTestCase(TestCase):
462 """A test case that wraps a test function.
464 This is useful for slipping pre-existing test functions into the
465 PyUnit framework. Optionally, set-up and tidy-up functions can be
466 supplied. As with TestCase, the tidy-up ('tearDown') function will
467 always be called if the set-up ('setUp') function ran successfully.
470 def __init__(self, testFunc, setUp=None, tearDown=None,
471 description=None):
472 TestCase.__init__(self)
473 self.__setUpFunc = setUp
474 self.__tearDownFunc = tearDown
475 self.__testFunc = testFunc
476 self.__description = description
478 def setUp(self):
479 if self.__setUpFunc is not None:
480 self.__setUpFunc()
482 def tearDown(self):
483 if self.__tearDownFunc is not None:
484 self.__tearDownFunc()
486 def runTest(self):
487 self.__testFunc()
489 def id(self):
490 return self.__testFunc.__name__
492 def __str__(self):
493 return "%s (%s)" % (self.__class__, self.__testFunc.__name__)
495 def __repr__(self):
496 return "<%s testFunc=%s>" % (self.__class__, self.__testFunc)
499 def describe(self):
500 if self.__description is not None: return self.__description
501 doc = self.__testFunc.__doc__
502 return doc and string.strip(string.split(doc, "\n")[0]) or None
504 ## aliases
505 shortDescription = describe
507 class TestSuite:
508 """A test suite is a composite test consisting of a number of TestCases.
510 For use, create an instance of TestSuite, then add test case instances.
511 When all tests have been added, the suite can be passed to a test
512 runner, such as TextTestRunner. It will run the individual test cases
513 in the order in which they were added, aggregating the results. When
514 subclassing, do not forget to call the base class constructor.
516 def __init__(self, tests=(), suiteName=None):
517 self._tests = []
518 self._testMap = {}
519 self.suiteName = suiteName
520 self.addTests(tests)
522 def __repr__(self):
523 return "<%s tests=%s>" % (self.__class__, pprint.pformat(self._tests))
525 __str__ = __repr__
527 def countTestCases(self):
528 cases = 0
529 for test in self._tests:
530 cases = cases + test.countTestCases()
531 return cases
533 def addTest(self, test):
534 self._tests.append(test)
535 if isinstance(test, TestSuite) and test.suiteName:
536 name = test.suiteName
537 elif isinstance(test, TestCase):
538 #print test, test._testMethodName
539 name = test._testMethodName
540 else:
541 name = test.__class__.__name__
542 self._testMap[name] = test
544 def addTests(self, tests):
545 for test in tests:
546 self.addTest(test)
548 def getTestForName(self, name):
549 return self._testMap[name]
551 def run(self, result):
552 return self(result)
554 def __call__(self, result):
555 for test in self._tests:
556 if result.shouldStop:
557 break
558 test(result)
559 return result
561 def debug(self):
562 """Run the tests without collecting errors in a TestResult"""
563 for test in self._tests: test.debug()
566 ##############################################################################
567 # Text UI
568 ##############################################################################
570 class StreamWrapper:
571 def __init__(self, out=sys.stdout, err=sys.stderr):
572 self._streamOut = out
573 self._streamErr = err
575 def write(self, txt):
576 self._streamOut.write(txt)
577 self._streamOut.flush()
579 def writeln(self, *lines):
580 for line in lines:
581 self.write(line + '\n')
582 if not lines:
583 self.write('\n')
585 def writeErr(self, txt):
586 self._streamErr.write(txt)
588 def writelnErr(self, *lines):
589 for line in lines:
590 self.writeErr(line + '\n')
591 if not lines:
592 self.writeErr('\n')
595 class _TextTestResult(TestResult, StreamWrapper):
596 _separatorWidth = 70
597 _sep1 = '='
598 _sep2 = '-'
599 _errorSep1 = '*'
600 _errorSep2 = '-'
601 _errorSep3 = ''
603 def __init__(self,
604 stream=sys.stdout,
605 errStream=sys.stderr,
606 verbosity=1,
607 explain=False):
609 TestResult.__init__(self)
610 StreamWrapper.__init__(self, out=stream, err=errStream)
612 self._verbosity = verbosity
613 self._showAll = verbosity > 1
614 self._dots = (verbosity == 1)
615 self._explain = explain
617 ## startup and shutdown methods
619 def beginTests(self):
620 self._startTime = time.time()
622 def endTests(self):
623 self._stopTime = time.time()
624 self._timeTaken = float(self._stopTime - self._startTime)
626 def stop(self):
627 self.shouldStop = 1
629 ## methods called for each test
631 def startTest(self, test):
632 TestResult.startTest(self, test)
633 if self._showAll:
634 self.write("%s (%s)" %( test.id(), test.describe() ) )
635 self.write(" ... ")
637 def addSuccess(self, test):
638 TestResult.addSuccess(self, test)
639 if self._showAll:
640 self.writeln("ok")
641 elif self._dots:
642 self.write('.')
644 def addError(self, test, err):
645 TestResult.addError(self, test, err)
646 if self._showAll:
647 self.writeln("ERROR")
648 elif self._dots:
649 self.write('E')
650 if err[0] is KeyboardInterrupt:
651 self.stop()
653 def addFailure(self, test, err):
654 TestResult.addFailure(self, test, err)
655 if self._showAll:
656 self.writeln("FAIL")
657 elif self._dots:
658 self.write('F')
660 ## display methods
662 def summarize(self):
663 self.printErrors()
664 self.writeSep2()
665 run = self.testsRun
666 self.writeln("Ran %d test%s in %.3fs" %
667 (run, run == 1 and "" or "s", self._timeTaken))
668 self.writeln()
669 if not self.wasSuccessful():
670 self.writeErr("FAILED (")
671 failed, errored = map(len, (self.failures, self.errors))
672 if failed:
673 self.writeErr("failures=%d" % failed)
674 if errored:
675 if failed: self.writeErr(", ")
676 self.writeErr("errors=%d" % errored)
677 self.writelnErr(")")
678 else:
679 self.writelnErr("OK")
681 def writeSep1(self):
682 self.writeln(self._sep1 * self._separatorWidth)
684 def writeSep2(self):
685 self.writeln(self._sep2 * self._separatorWidth)
687 def writeErrSep1(self):
688 self.writeln(self._errorSep1 * self._separatorWidth)
690 def writeErrSep2(self):
691 self.writeln(self._errorSep2 * self._separatorWidth)
693 def printErrors(self):
694 if self._dots or self._showAll:
695 self.writeln()
696 self.printErrorList('ERROR', self.errors)
697 self.printErrorList('FAIL', self.failures)
699 def printErrorList(self, flavour, errors):
700 for test, err in errors:
701 self.writeErrSep1()
702 self.writelnErr("%s %s (%s)" % (flavour, test.id(), test.describe() ))
703 if self._explain:
704 expln = test.explain()
705 if expln:
706 self.writeErrSep2()
707 self.writeErr( expln )
708 self.writelnErr()
710 self.writeErrSep2()
711 for line in apply(traceback.format_exception, err):
712 for l in line.split("\n")[:-1]:
713 self.writelnErr(l)
714 self.writelnErr("")
716 class TextTestRunner:
717 def __init__(self,
718 stream=sys.stdout,
719 errStream=sys.stderr,
720 verbosity=1,
721 explain=False):
723 self._out = stream
724 self._err = errStream
725 self._verbosity = verbosity
726 self._explain = explain
728 ## main methods
730 def run(self, test):
731 result = self._makeResult()
732 result.beginTests()
733 test( result )
734 result.endTests()
735 result.summarize()
737 return result
739 ## internal methods
741 def _makeResult(self):
742 return _TextTestResult(stream=self._out,
743 errStream=self._err,
744 verbosity=self._verbosity,
745 explain=self._explain,
748 ##############################################################################
749 # Locating and loading tests
750 ##############################################################################
752 class TestLoader:
753 """This class is responsible for loading tests according to various
754 criteria and returning them wrapped in a Test
756 testMethodPrefix = 'test'
757 sortTestMethodsUsing = cmp
758 suiteClass = TestSuite
760 def loadTestsFromTestCase(self, testCaseClass):
761 """Return a suite of all tests cases contained in testCaseClass"""
762 return self.suiteClass(tests=map(testCaseClass,
763 self.getTestCaseNames(testCaseClass)),
764 suiteName=testCaseClass.__name__)
766 def loadTestsFromModule(self, module):
767 """Return a suite of all tests cases contained in the given module"""
768 tests = []
769 for name in dir(module):
770 obj = getattr(module, name)
771 if type(obj) == types.ClassType and issubclass(obj, TestCase):
772 tests.append(self.loadTestsFromTestCase(obj))
773 return self.suiteClass(tests)
775 def loadTestsFromName(self, name, module=None):
776 """Return a suite of all tests cases given a string specifier.
778 The name may resolve either to a module, a test case class, a
779 test method within a test case class, or a callable object which
780 returns a TestCase or TestSuite instance.
782 The method optionally resolves the names relative to a given module.
784 parts = string.split(name, '.')
785 if module is None:
786 if not parts:
787 raise ValueError, "incomplete test name: %s" % name
788 else:
789 parts_copy = parts[:]
790 while parts_copy:
791 try:
792 module = __import__(string.join(parts_copy,'.'))
793 break
794 except ImportError:
795 del parts_copy[-1]
796 if not parts_copy: raise
797 parts = parts[1:]
798 obj = module
799 for part in parts:
800 if isinstance(obj, TestSuite):
801 obj = obj.getTestForName(part)
802 else:
803 obj = getattr(obj, part)
805 if type(obj) == types.ModuleType:
806 return self.loadTestsFromModule(obj)
807 elif type(obj) == types.ClassType and issubclass(obj, TestCase):
808 return self.loadTestsFromTestCase(obj)
809 elif type(obj) == types.UnboundMethodType:
810 return obj.im_class(obj.__name__)
811 elif isinstance(obj, TestSuite):
812 return obj
813 elif isinstance(obj, TestCase):
814 return obj
815 elif callable(obj):
816 test = obj()
817 if not isinstance(test, TestCase) and \
818 not isinstance(test, TestSuite):
819 raise ValueError, \
820 "calling %s returned %s, not a test" %(obj,test)
821 return test
822 else:
823 raise ValueError, "don't know how to make test from: %s" % obj
825 def loadTestsFromNames(self, names, module=None):
826 """Return a suite of all tests cases found using the given sequence
827 of string specifiers. See 'loadTestsFromName()'.
829 suites = []
830 for name in names:
831 suites.append(self.loadTestsFromName(name, module))
832 return self.suiteClass(suites)
834 def getTestCaseNames(self, testCaseClass):
835 """Return a sorted sequence of method names found within testCaseClass.
837 testFnNames = filter(lambda n,p=self.testMethodPrefix: n[:len(p)] == p,
838 dir(testCaseClass))
839 for baseclass in testCaseClass.__bases__:
840 for testFnName in self.getTestCaseNames(baseclass):
841 if testFnName not in testFnNames: # handle overridden methods
842 testFnNames.append(testFnName)
843 if self.sortTestMethodsUsing:
844 testFnNames.sort(self.sortTestMethodsUsing)
845 return testFnNames
849 defaultTestLoader = TestLoader()
852 ##############################################################################
853 # Patches for old functions: these functions should be considered obsolete
854 ##############################################################################
856 def _makeLoader(prefix, sortUsing, suiteClass=None):
857 loader = TestLoader()
858 loader.sortTestMethodsUsing = sortUsing
859 loader.testMethodPrefix = prefix
860 if suiteClass: loader.suiteClass = suiteClass
861 return loader
863 def getTestCaseNames(testCaseClass, prefix, sortUsing=cmp):
864 return _makeLoader(prefix, sortUsing).getTestCaseNames(testCaseClass)
866 def makeSuite(testCaseClass, prefix='test', sortUsing=cmp, suiteClass=TestSuite):
867 return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromTestCase(testCaseClass)
869 def findTestCases(module, prefix='test', sortUsing=cmp, suiteClass=TestSuite):
870 return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromModule(module)
872 ##############################################################################
873 # Facilities for running tests from the command line
874 ##############################################################################
876 class TestProgram:
877 """A command-line program that runs a set of tests; this is primarily
878 for making test modules conveniently executable.
880 USAGE = """\
881 Usage: %(progName)s [options] [test] [...]
883 Options:
884 -h, --help Show this message
885 -v, --verbose Verbose output
886 -q, --quiet Minimal output
887 -e, --expain Output extra test details if there is a failure or error
889 Examples:
890 %(progName)s - run default set of tests
891 %(progName)s MyTestSuite - run suite 'MyTestSuite'
892 %(progName)s MyTestSuite.MyTestCase - run suite 'MyTestSuite'
893 %(progName)s MyTestCase.testSomething - run MyTestCase.testSomething
894 %(progName)s MyTestCase - run all 'test*' test methods
895 in MyTestCase
897 def __init__(self, module='__main__', defaultTest=None,
898 argv=None, testRunner=None, testLoader=defaultTestLoader,
899 testSuite=None):
900 if type(module) == type(''):
901 self.module = __import__(module)
902 for part in string.split(module,'.')[1:]:
903 self.module = getattr(self.module, part)
904 else:
905 self.module = module
906 if argv is None:
907 argv = sys.argv
908 self.test = testSuite
909 self.verbosity = 1
910 self.explain = 0
911 self.defaultTest = defaultTest
912 self.testRunner = testRunner
913 self.testLoader = testLoader
914 self.progName = os.path.basename(argv[0])
915 self.parseArgs(argv)
916 self.runTests()
918 def usageExit(self, msg=None):
919 if msg: print msg
920 print self.USAGE % self.__dict__
921 sys.exit(2)
923 def parseArgs(self, argv):
924 import getopt
925 try:
926 options, args = getopt.getopt(argv[1:], 'hHvqer',
927 ['help','verbose','quiet','explain', 'raise'])
928 for opt, value in options:
929 if opt in ('-h','-H','--help'):
930 self.usageExit()
931 if opt in ('-q','--quiet'):
932 self.verbosity = 0
933 if opt in ('-v','--verbose'):
934 self.verbosity = 2
935 if opt in ('-e','--explain'):
936 self.explain = True
937 if len(args) == 0 and self.defaultTest is None and self.test is None:
938 self.test = self.testLoader.loadTestsFromModule(self.module)
939 return
940 if len(args) > 0:
941 self.testNames = args
942 else:
943 self.testNames = (self.defaultTest,)
944 self.createTests()
945 except getopt.error, msg:
946 self.usageExit(msg)
948 def createTests(self):
949 if self.test == None:
950 self.test = self.testLoader.loadTestsFromNames(self.testNames,
951 self.module)
953 def runTests(self):
954 if self.testRunner is None:
955 self.testRunner = TextTestRunner(verbosity=self.verbosity,
956 explain=self.explain)
957 result = self.testRunner.run(self.test)
958 self._cleanupAfterRunningTests()
959 sys.exit(not result.wasSuccessful())
961 def _cleanupAfterRunningTests(self):
962 """A hook method that is called immediately prior to calling
963 sys.exit(not result.wasSuccessful()) in self.runTests().
965 pass
967 main = TestProgram
970 ##############################################################################
971 # Executing this module from the command line
972 ##############################################################################
974 if __name__ == "__main__":
975 main(module=None)
977 # vim: shiftwidth=4 tabstop=4 expandtab