mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	Updated to latest PyUnit version (1.31 in PyUnit CVS); test_support.py
changed accordingly.
This commit is contained in:
		
							parent
							
								
									2e2cded1b5
								
							
						
					
					
						commit
						5ddd1a8dcb
					
				
					 2 changed files with 242 additions and 254 deletions
				
			
		|  | @ -102,12 +102,9 @@ def check_syntax(statement): | ||||||
| import unittest | import unittest | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class BasicTestRunner(unittest.VerboseTextTestRunner): | class BasicTestRunner: | ||||||
|     def __init__(self, stream=sys.stderr): |  | ||||||
|         unittest.VerboseTextTestRunner.__init__(self, stream, descriptions=0) |  | ||||||
| 
 |  | ||||||
|     def run(self, test): |     def run(self, test): | ||||||
|         result = unittest._VerboseTextTestResult(self.stream, descriptions=0) |         result = unittest.TestResult() | ||||||
|         test(result) |         test(result) | ||||||
|         return result |         return result | ||||||
| 
 | 
 | ||||||
|  | @ -115,13 +112,12 @@ def run(self, test): | ||||||
| def run_unittest(testclass): | def run_unittest(testclass): | ||||||
|     """Run tests from a unittest.TestCase-derived class.""" |     """Run tests from a unittest.TestCase-derived class.""" | ||||||
|     if verbose: |     if verbose: | ||||||
|         f = sys.stdout |         runner = unittest.TextTestRunner(sys.stdout, descriptions=0) | ||||||
|     else: |     else: | ||||||
|         import StringIO |         runner = BasicTestRunner() | ||||||
|         f = StringIO.StringIO() |  | ||||||
| 
 | 
 | ||||||
|     suite = unittest.makeSuite(testclass) |     suite = unittest.makeSuite(testclass) | ||||||
|     result = BasicTestRunner(stream=f).run(suite) |     result = runner.run(suite) | ||||||
|     if result.errors or result.failures: |     if not result.wasSuccessful(): | ||||||
|         raise TestFailed("errors occurred in %s.%s" |         raise TestFailed("errors occurred in %s.%s" | ||||||
|                          % (testclass.__module__, testclass.__name__)) |                          % (testclass.__module__, testclass.__name__)) | ||||||
|  |  | ||||||
							
								
								
									
										456
									
								
								Lib/unittest.py
									
										
									
									
									
								
							
							
						
						
									
										456
									
								
								Lib/unittest.py
									
										
									
									
									
								
							|  | @ -1,17 +1,32 @@ | ||||||
| #!/usr/bin/env python | #!/usr/bin/env python | ||||||
| """ | ''' | ||||||
| Python unit testing framework, based on Erich Gamma's JUnit and Kent Beck's | Python unit testing framework, based on Erich Gamma's JUnit and Kent Beck's | ||||||
| Smalltalk testing framework. | Smalltalk testing framework. | ||||||
| 
 | 
 | ||||||
| Further information is available in the bundled documentation, and from |  | ||||||
| 
 |  | ||||||
|   http://pyunit.sourceforge.net/ |  | ||||||
| 
 |  | ||||||
| This module contains the core framework classes that form the basis of | This module contains the core framework classes that form the basis of | ||||||
| specific test cases and suites (TestCase, TestSuite etc.), and also a | specific test cases and suites (TestCase, TestSuite etc.), and also a | ||||||
| text-based utility class for running the tests and reporting the results | text-based utility class for running the tests and reporting the results | ||||||
| (TextTestRunner). | (TextTestRunner). | ||||||
| 
 | 
 | ||||||
|  | Simple usage: | ||||||
|  | 
 | ||||||
|  |     import unittest | ||||||
|  | 
 | ||||||
|  |     class IntegerArithmenticTestCase(unittest.TestCase): | ||||||
|  |         def testAdd(self):  ## test method names begin 'test*' | ||||||
|  |             self.assertEquals((1 + 2), 3) | ||||||
|  |             self.assertEquals(0 + 1, 1) | ||||||
|  |         def testMultiply(self); | ||||||
|  |             self.assertEquals((0 * 10), 0) | ||||||
|  |             self.assertEquals((5 * 8), 40) | ||||||
|  | 
 | ||||||
|  |     if __name__ == '__main__': | ||||||
|  |         unittest.main() | ||||||
|  | 
 | ||||||
|  | Further information is available in the bundled documentation, and from | ||||||
|  | 
 | ||||||
|  |   http://pyunit.sourceforge.net/ | ||||||
|  | 
 | ||||||
| Copyright (c) 1999, 2000, 2001 Steve Purcell | Copyright (c) 1999, 2000, 2001 Steve Purcell | ||||||
| This module is free software, and you may redistribute it and/or modify | This module is free software, and you may redistribute it and/or modify | ||||||
| it under the same terms as Python itself, so long as this copyright message | it under the same terms as Python itself, so long as this copyright message | ||||||
|  | @ -27,9 +42,10 @@ | ||||||
| PARTICULAR PURPOSE.  THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, | PARTICULAR PURPOSE.  THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, | ||||||
| AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, | AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, | ||||||
| SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. | SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. | ||||||
| """ | ''' | ||||||
| 
 | 
 | ||||||
| __author__ = "Steve Purcell (stephen_purcell@yahoo.com)" | __author__ = "Steve Purcell" | ||||||
|  | __email__ = "stephen_purcell at yahoo dot com" | ||||||
| __version__ = "$Revision$"[11:-2] | __version__ = "$Revision$"[11:-2] | ||||||
| 
 | 
 | ||||||
| import time | import time | ||||||
|  | @ -37,15 +53,7 @@ | ||||||
| import traceback | import traceback | ||||||
| import string | import string | ||||||
| import os | import os | ||||||
| 
 | import types | ||||||
| ############################################################################## |  | ||||||
| # A platform-specific concession to help the code work for JPython users |  | ||||||
| ############################################################################## |  | ||||||
| 
 |  | ||||||
| plat = string.lower(sys.platform) |  | ||||||
| _isJPython = string.find(plat, 'java') >= 0 or string.find(plat, 'jdk') >= 0 |  | ||||||
| del plat |  | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| ############################################################################## | ############################################################################## | ||||||
| # Test framework core | # Test framework core | ||||||
|  | @ -84,6 +92,10 @@ def addFailure(self, test, err): | ||||||
|         "Called when a failure has occurred" |         "Called when a failure has occurred" | ||||||
|         self.failures.append((test, err)) |         self.failures.append((test, err)) | ||||||
| 
 | 
 | ||||||
|  |     def addSuccess(self, test): | ||||||
|  |         "Called when a test has completed successfully" | ||||||
|  |         pass | ||||||
|  | 
 | ||||||
|     def wasSuccessful(self): |     def wasSuccessful(self): | ||||||
|         "Tells whether or not this result was a success" |         "Tells whether or not this result was a success" | ||||||
|         return len(self.failures) == len(self.errors) == 0 |         return len(self.failures) == len(self.errors) == 0 | ||||||
|  | @ -101,10 +113,6 @@ def __repr__(self): | ||||||
| class TestCase: | class TestCase: | ||||||
|     """A class whose instances are single test cases. |     """A class whose instances are single test cases. | ||||||
| 
 | 
 | ||||||
|     Test authors should subclass TestCase for their own tests. Construction  |  | ||||||
|     and deconstruction of the test's environment ('fixture') can be |  | ||||||
|     implemented by overriding the 'setUp' and 'tearDown' methods respectively. |  | ||||||
| 
 |  | ||||||
|     By default, the test code itself should be placed in a method named |     By default, the test code itself should be placed in a method named | ||||||
|     'runTest'. |     'runTest'. | ||||||
| 
 | 
 | ||||||
|  | @ -112,6 +120,16 @@ class TestCase: | ||||||
|     many test methods as are needed. When instantiating such a TestCase |     many test methods as are needed. When instantiating such a TestCase | ||||||
|     subclass, specify in the constructor arguments the name of the test method |     subclass, specify in the constructor arguments the name of the test method | ||||||
|     that the instance is to execute. |     that the instance is to execute. | ||||||
|  | 
 | ||||||
|  |     Test authors should subclass TestCase for their own tests. Construction  | ||||||
|  |     and deconstruction of the test's environment ('fixture') can be | ||||||
|  |     implemented by overriding the 'setUp' and 'tearDown' methods respectively. | ||||||
|  | 
 | ||||||
|  |     If it is necessary to override the __init__ method, the base class | ||||||
|  |     __init__ method must always be called. It is important that subclasses | ||||||
|  |     should not change the signature of their __init__ method, since instances | ||||||
|  |     of the classes are instantiated automatically by parts of the framework | ||||||
|  |     in order to be run. | ||||||
|     """ |     """ | ||||||
|     def __init__(self, methodName='runTest'): |     def __init__(self, methodName='runTest'): | ||||||
|         """Create an instance of the class that will use the named test |         """Create an instance of the class that will use the named test | ||||||
|  | @ -119,7 +137,9 @@ def __init__(self, methodName='runTest'): | ||||||
|            not have a method with the specified name. |            not have a method with the specified name. | ||||||
|         """ |         """ | ||||||
|         try: |         try: | ||||||
|             self.__testMethod = getattr(self,methodName) |             self.__testMethodName = methodName | ||||||
|  |             testMethod = getattr(self, methodName) | ||||||
|  |             self.__testMethodDoc = testMethod.__doc__ | ||||||
|         except AttributeError: |         except AttributeError: | ||||||
|             raise ValueError, "no such test method in %s: %s" % \ |             raise ValueError, "no such test method in %s: %s" % \ | ||||||
|                   (self.__class__, methodName) |                   (self.__class__, methodName) | ||||||
|  | @ -145,18 +165,18 @@ def shortDescription(self): | ||||||
|         The default implementation of this method returns the first line of |         The default implementation of this method returns the first line of | ||||||
|         the specified test method's docstring. |         the specified test method's docstring. | ||||||
|         """ |         """ | ||||||
|         doc = self.__testMethod.__doc__ |         doc = self.__testMethodDoc | ||||||
|         return doc and string.strip(string.split(doc, "\n")[0]) or None |         return doc and string.strip(string.split(doc, "\n")[0]) or None | ||||||
| 
 | 
 | ||||||
|     def id(self): |     def id(self): | ||||||
|         return "%s.%s" % (self.__class__, self.__testMethod.__name__) |         return "%s.%s" % (self.__class__, self.__testMethodName) | ||||||
| 
 | 
 | ||||||
|     def __str__(self): |     def __str__(self): | ||||||
|         return "%s (%s)" % (self.__testMethod.__name__, self.__class__) |         return "%s (%s)" % (self.__testMethodName, self.__class__) | ||||||
| 
 | 
 | ||||||
|     def __repr__(self): |     def __repr__(self): | ||||||
|         return "<%s testMethod=%s>" % \ |         return "<%s testMethod=%s>" % \ | ||||||
|                (self.__class__, self.__testMethod.__name__) |                (self.__class__, self.__testMethodName) | ||||||
| 
 | 
 | ||||||
|     def run(self, result=None): |     def run(self, result=None): | ||||||
|         return self(result) |         return self(result) | ||||||
|  | @ -164,6 +184,7 @@ def run(self, result=None): | ||||||
|     def __call__(self, result=None): |     def __call__(self, result=None): | ||||||
|         if result is None: result = self.defaultTestResult() |         if result is None: result = self.defaultTestResult() | ||||||
|         result.startTest(self) |         result.startTest(self) | ||||||
|  |         testMethod = getattr(self, self.__testMethodName) | ||||||
|         try: |         try: | ||||||
|             try: |             try: | ||||||
|                 self.setUp() |                 self.setUp() | ||||||
|  | @ -171,8 +192,10 @@ def __call__(self, result=None): | ||||||
|                 result.addError(self,self.__exc_info()) |                 result.addError(self,self.__exc_info()) | ||||||
|                 return |                 return | ||||||
| 
 | 
 | ||||||
|  |             ok = 0 | ||||||
|             try: |             try: | ||||||
|                 self.__testMethod() |                 testMethod() | ||||||
|  |                 ok = 1 | ||||||
|             except AssertionError, e: |             except AssertionError, e: | ||||||
|                 result.addFailure(self,self.__exc_info()) |                 result.addFailure(self,self.__exc_info()) | ||||||
|             except: |             except: | ||||||
|  | @ -182,12 +205,15 @@ def __call__(self, result=None): | ||||||
|                 self.tearDown() |                 self.tearDown() | ||||||
|             except: |             except: | ||||||
|                 result.addError(self,self.__exc_info()) |                 result.addError(self,self.__exc_info()) | ||||||
|  |                 ok = 0 | ||||||
|  |             if ok: result.addSuccess(self) | ||||||
|         finally: |         finally: | ||||||
|             result.stopTest(self) |             result.stopTest(self) | ||||||
| 
 | 
 | ||||||
|     def debug(self): |     def debug(self): | ||||||
|  |         """Run the test without collecting errors in a TestResult""" | ||||||
|         self.setUp() |         self.setUp() | ||||||
|         self.__testMethod() |         getattr(self, self.__testMethodName)() | ||||||
|         self.tearDown() |         self.tearDown() | ||||||
| 
 | 
 | ||||||
|     def assert_(self, expr, msg=None): |     def assert_(self, expr, msg=None): | ||||||
|  | @ -220,6 +246,22 @@ def assertRaises(self, excClass, callableObj, *args, **kwargs): | ||||||
|             else: excName = str(excClass) |             else: excName = str(excClass) | ||||||
|             raise AssertionError, excName |             raise AssertionError, excName | ||||||
| 
 | 
 | ||||||
|  |     def assertEquals(self, first, second, msg=None): | ||||||
|  |         """Assert that the two objects are equal as determined by the '==' | ||||||
|  |            operator. | ||||||
|  |         """ | ||||||
|  |         self.assert_((first == second), msg or '%s != %s' % (first, second)) | ||||||
|  | 
 | ||||||
|  |     def assertNotEquals(self, first, second, msg=None): | ||||||
|  |         """Assert that the two objects are unequal as determined by the '!=' | ||||||
|  |            operator. | ||||||
|  |         """ | ||||||
|  |         self.assert_((first != second), msg or '%s == %s' % (first, second)) | ||||||
|  | 
 | ||||||
|  |     assertEqual = assertEquals | ||||||
|  | 
 | ||||||
|  |     assertNotEqual = assertNotEquals | ||||||
|  | 
 | ||||||
|     def fail(self, msg=None): |     def fail(self, msg=None): | ||||||
|         """Fail immediately, with the given message.""" |         """Fail immediately, with the given message.""" | ||||||
|         raise AssertionError, msg |         raise AssertionError, msg | ||||||
|  | @ -278,10 +320,10 @@ def __call__(self, result): | ||||||
|         return result |         return result | ||||||
| 
 | 
 | ||||||
|     def debug(self): |     def debug(self): | ||||||
|  |         """Run the tests without collecting errors in a TestResult""" | ||||||
|         for test in self._tests: test.debug() |         for test in self._tests: test.debug() | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| class FunctionTestCase(TestCase): | class FunctionTestCase(TestCase): | ||||||
|     """A test case that wraps a test function. |     """A test case that wraps a test function. | ||||||
| 
 | 
 | ||||||
|  | @ -327,84 +369,100 @@ def shortDescription(self): | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| ############################################################################## | ############################################################################## | ||||||
| # Convenience functions | # Locating and loading tests | ||||||
| ############################################################################## | ############################################################################## | ||||||
| 
 | 
 | ||||||
| def getTestCaseNames(testCaseClass, prefix, sortUsing=cmp): | class TestLoader: | ||||||
|     """Extracts all the names of functions in the given test case class |     """This class is responsible for loading tests according to various | ||||||
|        and its base classes that start with the given prefix. This is used |     criteria and returning them wrapped in a Test | ||||||
|        by makeSuite(). | 
 | ||||||
|  |     It can load all tests within a given, module | ||||||
|     """ |     """ | ||||||
|     testFnNames = filter(lambda n,p=prefix: n[:len(p)] == p, |     testMethodPrefix = 'test' | ||||||
|  |     sortTestMethodsUsing = cmp | ||||||
|  |     suiteClass = TestSuite | ||||||
|  | 
 | ||||||
|  |     def loadTestsFromTestCase(self, testCaseClass): | ||||||
|  |         return self.suiteClass(map(testCaseClass, | ||||||
|  |                                    self.getTestCaseNames(testCaseClass))) | ||||||
|  | 
 | ||||||
|  |     def loadTestsFromModule(self, module): | ||||||
|  |         tests = [] | ||||||
|  |         for name in dir(module): | ||||||
|  |             obj = getattr(module, name) | ||||||
|  |             if type(obj) == types.ClassType and issubclass(obj, TestCase): | ||||||
|  |                 tests.append(self.loadTestsFromTestCase(obj)) | ||||||
|  |         return self.suiteClass(tests) | ||||||
|  | 
 | ||||||
|  |     def loadTestsFromName(self, name, module=None): | ||||||
|  |         parts = string.split(name, '.') | ||||||
|  |         if module is None: | ||||||
|  |             if not parts: | ||||||
|  |                 raise ValueError, "incomplete test name: %s" % name | ||||||
|  |             else: | ||||||
|  |                 module = __import__(parts) | ||||||
|  |                 parts = parts[1:] | ||||||
|  |         obj = module | ||||||
|  |         for part in parts: | ||||||
|  |             obj = getattr(obj, part) | ||||||
|  | 
 | ||||||
|  |         if type(obj) == types.ModuleType: | ||||||
|  |             return self.loadTestsFromModule(obj) | ||||||
|  |         elif type(obj) == types.ClassType and issubclass(obj, TestCase): | ||||||
|  |             return self.loadTestsFromTestCase(obj) | ||||||
|  |         elif type(obj) == types.UnboundMethodType: | ||||||
|  |             return obj.im_class(obj.__name__) | ||||||
|  |         elif callable(obj): | ||||||
|  |             test = obj() | ||||||
|  |             if not isinstance(test, TestCase) and \ | ||||||
|  |                not isinstance(test, TestSuite): | ||||||
|  |                 raise ValueError, \ | ||||||
|  |                       "calling %s returned %s, not a test" % obj,test | ||||||
|  |             return test | ||||||
|  |         else: | ||||||
|  |             raise ValueError, "don't know how to make test from: %s" % obj | ||||||
|  | 
 | ||||||
|  |     def loadTestsFromNames(self, names, module=None): | ||||||
|  |         suites = [] | ||||||
|  |         for name in names: | ||||||
|  |             suites.append(self.loadTestsFromName(name, module)) | ||||||
|  |         return self.suiteClass(suites) | ||||||
|  | 
 | ||||||
|  |     def getTestCaseNames(self, testCaseClass): | ||||||
|  |         testFnNames = filter(lambda n,p=self.testMethodPrefix: n[:len(p)] == p, | ||||||
|                              dir(testCaseClass)) |                              dir(testCaseClass)) | ||||||
|         for baseclass in testCaseClass.__bases__: |         for baseclass in testCaseClass.__bases__: | ||||||
|         testFnNames = testFnNames + \ |             for testFnName in self.getTestCaseNames(baseclass): | ||||||
|                       getTestCaseNames(baseclass, prefix, sortUsing=None) |                 if testFnName not in testFnNames:  # handle overridden methods | ||||||
|     if sortUsing: |                     testFnNames.append(testFnName) | ||||||
|         testFnNames.sort(sortUsing) |         if self.sortTestMethodsUsing: | ||||||
|  |             testFnNames.sort(self.sortTestMethodsUsing) | ||||||
|         return testFnNames |         return testFnNames | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def makeSuite(testCaseClass, prefix='test', sortUsing=cmp): | 
 | ||||||
|     """Returns a TestSuite instance built from all of the test functions | defaultTestLoader = TestLoader() | ||||||
|        in the given test case class whose names begin with the given |  | ||||||
|        prefix. The cases are sorted by their function names |  | ||||||
|        using the supplied comparison function, which defaults to 'cmp'. |  | ||||||
|     """ |  | ||||||
|     cases = map(testCaseClass, |  | ||||||
|                 getTestCaseNames(testCaseClass, prefix, sortUsing)) |  | ||||||
|     return TestSuite(cases) |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def createTestInstance(name, module=None): | ############################################################################## | ||||||
|     """Finds tests by their name, optionally only within the given module. | # Patches for old functions: these functions should be considered obsolete | ||||||
|  | ############################################################################## | ||||||
| 
 | 
 | ||||||
|     Return the newly-constructed test, ready to run. If the name contains a ':' | def _makeLoader(prefix, sortUsing, suiteClass=None): | ||||||
|     then the portion of the name after the colon is used to find a specific |     loader = TestLoader() | ||||||
|     test case within the test case class named before the colon. |     loader.sortTestMethodsUsing = sortUsing | ||||||
|  |     loader.testMethodPrefix = prefix | ||||||
|  |     if suiteClass: loader.suiteClass = suiteClass | ||||||
|  |     return loader | ||||||
| 
 | 
 | ||||||
|     Examples: | def getTestCaseNames(testCaseClass, prefix, sortUsing=cmp): | ||||||
|      findTest('examples.listtests.suite') |     return _makeLoader(prefix, sortUsing).getTestCaseNames(testCaseClass) | ||||||
|         -- returns result of calling 'suite' |  | ||||||
|      findTest('examples.listtests.ListTestCase:checkAppend') |  | ||||||
|         -- returns result of calling ListTestCase('checkAppend') |  | ||||||
|      findTest('examples.listtests.ListTestCase:check-') |  | ||||||
|         -- returns result of calling makeSuite(ListTestCase, prefix="check") |  | ||||||
|     """ |  | ||||||
| 
 | 
 | ||||||
|     spec = string.split(name, ':') | def makeSuite(testCaseClass, prefix='test', sortUsing=cmp, suiteClass=TestSuite): | ||||||
|     if len(spec) > 2: raise ValueError, "illegal test name: %s" % name |     return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromTestCase(testCaseClass) | ||||||
|     if len(spec) == 1: | 
 | ||||||
|         testName = spec[0] | def findTestCases(module, prefix='test', sortUsing=cmp, suiteClass=TestSuite): | ||||||
|         caseName = None |     return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromModule(module) | ||||||
|     else: |  | ||||||
|         testName, caseName = spec |  | ||||||
|     parts = string.split(testName, '.') |  | ||||||
|     if module is None: |  | ||||||
|         if len(parts) < 2: |  | ||||||
|             raise ValueError, "incomplete test name: %s" % name |  | ||||||
|         constructor = __import__(string.join(parts[:-1],'.')) |  | ||||||
|         parts = parts[1:] |  | ||||||
|     else: |  | ||||||
|         constructor = module |  | ||||||
|     for part in parts: |  | ||||||
|         constructor = getattr(constructor, part) |  | ||||||
|     if not callable(constructor): |  | ||||||
|         raise ValueError, "%s is not a callable object" % constructor |  | ||||||
|     if caseName: |  | ||||||
|         if caseName[-1] == '-': |  | ||||||
|             prefix = caseName[:-1] |  | ||||||
|             if not prefix: |  | ||||||
|                 raise ValueError, "prefix too short: %s" % name |  | ||||||
|             test = makeSuite(constructor, prefix=prefix) |  | ||||||
|         else: |  | ||||||
|             test = constructor(caseName) |  | ||||||
|     else: |  | ||||||
|         test = constructor() |  | ||||||
|     if not hasattr(test,"countTestCases"): |  | ||||||
|         raise TypeError, \ |  | ||||||
|               "object %s found with spec %s is not a test" % (test, name) |  | ||||||
|     return test |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| ############################################################################## | ############################################################################## | ||||||
|  | @ -415,181 +473,107 @@ class _WritelnDecorator: | ||||||
|     """Used to decorate file-like objects with a handy 'writeln' method""" |     """Used to decorate file-like objects with a handy 'writeln' method""" | ||||||
|     def __init__(self,stream): |     def __init__(self,stream): | ||||||
|         self.stream = stream |         self.stream = stream | ||||||
|         if _isJPython: |  | ||||||
|             import java.lang.System |  | ||||||
|             self.linesep = java.lang.System.getProperty("line.separator") |  | ||||||
|         else: |  | ||||||
|             self.linesep = os.linesep |  | ||||||
| 
 | 
 | ||||||
|     def __getattr__(self, attr): |     def __getattr__(self, attr): | ||||||
|         return getattr(self.stream,attr) |         return getattr(self.stream,attr) | ||||||
| 
 | 
 | ||||||
|     def writeln(self, *args): |     def writeln(self, *args): | ||||||
|         if args: apply(self.write, args) |         if args: apply(self.write, args) | ||||||
|         self.write(self.linesep) |         self.write('\n') # text-mode streams translate to \r\n if needed | ||||||
|   |   | ||||||
| 
 | 
 | ||||||
| class _JUnitTextTestResult(TestResult): | class _TextTestResult(TestResult): | ||||||
|     """A test result class that can print formatted text results to a stream. |     """A test result class that can print formatted text results to a stream. | ||||||
| 
 | 
 | ||||||
|     Used by JUnitTextTestRunner. |     Used by TextTestRunner. | ||||||
|     """ |     """ | ||||||
|     def __init__(self, stream): |     separator1 = '=' * 70 | ||||||
|         self.stream = stream |     separator2 = '-' * 70 | ||||||
|         TestResult.__init__(self) |  | ||||||
| 
 | 
 | ||||||
|     def addError(self, test, error): |     def __init__(self, stream, descriptions, verbosity): | ||||||
|         TestResult.addError(self,test,error) |  | ||||||
|         self.stream.write('E') |  | ||||||
|         self.stream.flush() |  | ||||||
|         if error[0] is KeyboardInterrupt: |  | ||||||
|             self.shouldStop = 1 |  | ||||||
|   |  | ||||||
|     def addFailure(self, test, error): |  | ||||||
|         TestResult.addFailure(self,test,error) |  | ||||||
|         self.stream.write('F') |  | ||||||
|         self.stream.flush() |  | ||||||
|   |  | ||||||
|     def startTest(self, test): |  | ||||||
|         TestResult.startTest(self,test) |  | ||||||
|         self.stream.write('.') |  | ||||||
|         self.stream.flush() |  | ||||||
| 
 |  | ||||||
|     def printNumberedErrors(self,errFlavour,errors): |  | ||||||
|         if not errors: return |  | ||||||
|         if len(errors) == 1: |  | ||||||
|             self.stream.writeln("There was 1 %s:" % errFlavour) |  | ||||||
|         else: |  | ||||||
|             self.stream.writeln("There were %i %ss:" % |  | ||||||
|                                 (len(errors), errFlavour)) |  | ||||||
|         i = 1 |  | ||||||
|         for test,error in errors: |  | ||||||
|             errString = string.join(apply(traceback.format_exception,error),"") |  | ||||||
|             self.stream.writeln("%i) %s" % (i, test)) |  | ||||||
|             self.stream.writeln(errString) |  | ||||||
|             i = i + 1 |  | ||||||
|   |  | ||||||
|     def printErrors(self): |  | ||||||
|         self.printNumberedErrors("error",self.errors) |  | ||||||
| 
 |  | ||||||
|     def printFailures(self): |  | ||||||
|         self.printNumberedErrors("failure",self.failures) |  | ||||||
| 
 |  | ||||||
|     def printHeader(self): |  | ||||||
|         self.stream.writeln() |  | ||||||
|         if self.wasSuccessful(): |  | ||||||
|             self.stream.writeln("OK (%i tests)" % self.testsRun) |  | ||||||
|         else: |  | ||||||
|             self.stream.writeln("!!!FAILURES!!!") |  | ||||||
|             self.stream.writeln("Test Results") |  | ||||||
|             self.stream.writeln() |  | ||||||
|             self.stream.writeln("Run: %i ; Failures: %i ; Errors: %i" % |  | ||||||
|                                 (self.testsRun, len(self.failures), |  | ||||||
|                                  len(self.errors))) |  | ||||||
|              |  | ||||||
|     def printResult(self): |  | ||||||
|         self.printHeader() |  | ||||||
|         self.printErrors() |  | ||||||
|         self.printFailures() |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class JUnitTextTestRunner: |  | ||||||
|     """A test runner class that displays results in textual form. |  | ||||||
|      |  | ||||||
|     The display format approximates that of JUnit's 'textui' test runner. |  | ||||||
|     This test runner may be removed in a future version of PyUnit. |  | ||||||
|     """ |  | ||||||
|     def __init__(self, stream=sys.stderr): |  | ||||||
|         self.stream = _WritelnDecorator(stream) |  | ||||||
| 
 |  | ||||||
|     def run(self, test): |  | ||||||
|         "Run the given test case or test suite." |  | ||||||
|         result = _JUnitTextTestResult(self.stream) |  | ||||||
|         startTime = time.time() |  | ||||||
|         test(result) |  | ||||||
|         stopTime = time.time() |  | ||||||
|         self.stream.writeln() |  | ||||||
|         self.stream.writeln("Time: %.3fs" % float(stopTime - startTime)) |  | ||||||
|         result.printResult() |  | ||||||
|         return result |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| ############################################################################## |  | ||||||
| # Verbose text UI |  | ||||||
| ############################################################################## |  | ||||||
| 
 |  | ||||||
| class _VerboseTextTestResult(TestResult): |  | ||||||
|     """A test result class that can print formatted text results to a stream. |  | ||||||
| 
 |  | ||||||
|     Used by VerboseTextTestRunner. |  | ||||||
|     """ |  | ||||||
|     def __init__(self, stream, descriptions): |  | ||||||
|         TestResult.__init__(self) |         TestResult.__init__(self) | ||||||
|         self.stream = stream |         self.stream = stream | ||||||
|         self.lastFailure = None |         self.showAll = verbosity > 1 | ||||||
|  |         self.dots = verbosity == 1 | ||||||
|         self.descriptions = descriptions |         self.descriptions = descriptions | ||||||
| 
 | 
 | ||||||
|  |     def getDescription(self, test): | ||||||
|  |         if self.descriptions: | ||||||
|  |             return test.shortDescription() or str(test) | ||||||
|  |         else: | ||||||
|  |             return str(test) | ||||||
|  | 
 | ||||||
|     def startTest(self, test): |     def startTest(self, test): | ||||||
|         TestResult.startTest(self, test) |         TestResult.startTest(self, test) | ||||||
|         if self.descriptions: |         if self.showAll: | ||||||
|             self.stream.write(test.shortDescription() or str(test)) |             self.stream.write(self.getDescription(test)) | ||||||
|         else: |  | ||||||
|             self.stream.write(str(test)) |  | ||||||
|             self.stream.write(" ... ") |             self.stream.write(" ... ") | ||||||
| 
 | 
 | ||||||
|     def stopTest(self, test): |     def addSuccess(self, test): | ||||||
|         TestResult.stopTest(self, test) |         TestResult.addSuccess(self, test) | ||||||
|         if self.lastFailure is not test: |         if self.showAll: | ||||||
|             self.stream.writeln("ok") |             self.stream.writeln("ok") | ||||||
|  |         elif self.dots: | ||||||
|  |             self.stream.write('.') | ||||||
| 
 | 
 | ||||||
|     def addError(self, test, err): |     def addError(self, test, err): | ||||||
|         TestResult.addError(self, test, err) |         TestResult.addError(self, test, err) | ||||||
|         self._printError("ERROR", test, err) |         if self.showAll: | ||||||
|         self.lastFailure = test |             self.stream.writeln("ERROR") | ||||||
|  |         elif self.dots: | ||||||
|  |             self.stream.write('E') | ||||||
|         if err[0] is KeyboardInterrupt: |         if err[0] is KeyboardInterrupt: | ||||||
|             self.shouldStop = 1 |             self.shouldStop = 1 | ||||||
| 
 | 
 | ||||||
|     def addFailure(self, test, err): |     def addFailure(self, test, err): | ||||||
|         TestResult.addFailure(self, test, err) |         TestResult.addFailure(self, test, err) | ||||||
|         self._printError("FAIL", test, err) |         if self.showAll: | ||||||
|         self.lastFailure = test |             self.stream.writeln("FAIL") | ||||||
|  |         elif self.dots: | ||||||
|  |             self.stream.write('F') | ||||||
| 
 | 
 | ||||||
|     def _printError(self, flavour, test, err): |     def printErrors(self): | ||||||
|         errLines = [] |         if self.dots or self.showAll: | ||||||
|         separator1 = "\t" + '=' * 70 |  | ||||||
|         separator2 = "\t" + '-' * 70 |  | ||||||
|         if not self.lastFailure is test: |  | ||||||
|             self.stream.writeln() |             self.stream.writeln() | ||||||
|             self.stream.writeln(separator1) |         self.printErrorList('ERROR', self.errors) | ||||||
|         self.stream.writeln("\t%s" % flavour) |         self.printErrorList('FAIL', self.failures) | ||||||
|         self.stream.writeln(separator2) | 
 | ||||||
|  |     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) | ||||||
|             for line in apply(traceback.format_exception, err): |             for line in apply(traceback.format_exception, err): | ||||||
|                 for l in string.split(line,"\n")[:-1]: |                 for l in string.split(line,"\n")[:-1]: | ||||||
|                 self.stream.writeln("\t%s" % l) |                     self.stream.writeln("%s" % l) | ||||||
|         self.stream.writeln(separator1) |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class VerboseTextTestRunner: | class TextTestRunner: | ||||||
|     """A test runner class that displays results in textual form. |     """A test runner class that displays results in textual form. | ||||||
|      |      | ||||||
|     It prints out the names of tests as they are run, errors as they |     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. |     occur, and a summary of the results at the end of the test run. | ||||||
|     """ |     """ | ||||||
|     def __init__(self, stream=sys.stderr, descriptions=1): |     def __init__(self, stream=sys.stderr, descriptions=1, verbosity=1): | ||||||
|         self.stream = _WritelnDecorator(stream) |         self.stream = _WritelnDecorator(stream) | ||||||
|         self.descriptions = descriptions |         self.descriptions = descriptions | ||||||
|  |         self.verbosity = verbosity | ||||||
|  | 
 | ||||||
|  |     def _makeResult(self): | ||||||
|  |         return _TextTestResult(self.stream, self.descriptions, self.verbosity) | ||||||
| 
 | 
 | ||||||
|     def run(self, test): |     def run(self, test): | ||||||
|         "Run the given test case or test suite." |         "Run the given test case or test suite." | ||||||
|         result = _VerboseTextTestResult(self.stream, self.descriptions) |         result = self._makeResult() | ||||||
|         startTime = time.time() |         startTime = time.time() | ||||||
|         test(result) |         test(result) | ||||||
|         stopTime = time.time() |         stopTime = time.time() | ||||||
|         timeTaken = float(stopTime - startTime) |         timeTaken = float(stopTime - startTime) | ||||||
|         self.stream.writeln("-" * 78) |         result.printErrors() | ||||||
|  |         self.stream.writeln(result.separator2) | ||||||
|         run = result.testsRun |         run = result.testsRun | ||||||
|         self.stream.writeln("Ran %d test%s in %.3fs" % |         self.stream.writeln("Ran %d test%s in %.3fs" % | ||||||
|                             (run, run > 1 and "s" or "", timeTaken)) |                             (run, run == 1 and "" or "s", timeTaken)) | ||||||
|         self.stream.writeln() |         self.stream.writeln() | ||||||
|         if not result.wasSuccessful(): |         if not result.wasSuccessful(): | ||||||
|             self.stream.write("FAILED (") |             self.stream.write("FAILED (") | ||||||
|  | @ -605,9 +589,6 @@ def run(self, test): | ||||||
|         return result |         return result | ||||||
|          |          | ||||||
| 
 | 
 | ||||||
| # Which flavour of TextTestRunner is the default? |  | ||||||
| TextTestRunner = VerboseTextTestRunner |  | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| ############################################################################## | ############################################################################## | ||||||
| # Facilities for running tests from the command line | # Facilities for running tests from the command line | ||||||
|  | @ -618,17 +599,22 @@ class TestProgram: | ||||||
|        for making test modules conveniently executable. |        for making test modules conveniently executable. | ||||||
|     """ |     """ | ||||||
|     USAGE = """\ |     USAGE = """\ | ||||||
| Usage: %(progName)s [-h|--help] [test[:(casename|prefix-)]] [...] | Usage: %(progName)s [options] [test[:(casename|prefix-)]] [...] | ||||||
|  | 
 | ||||||
|  | Options: | ||||||
|  |   -h, --help       Show this message | ||||||
|  |   -v, --verbose    Verbose output | ||||||
|  |   -q, --quiet      Minimal output | ||||||
| 
 | 
 | ||||||
| Examples: | Examples: | ||||||
|   %(progName)s                               - run default set of tests |   %(progName)s                               - run default set of tests | ||||||
|   %(progName)s MyTestSuite                   - run suite 'MyTestSuite' |   %(progName)s MyTestSuite                   - run suite 'MyTestSuite' | ||||||
|   %(progName)s MyTestCase:checkSomething     - run MyTestCase.checkSomething |   %(progName)s MyTestCase.testSomething      - run MyTestCase.testSomething | ||||||
|   %(progName)s MyTestCase:check-             - run all 'check*' test methods |   %(progName)s MyTestCase                    - run all 'test*' test methods | ||||||
|                                                in MyTestCase |                                                in MyTestCase | ||||||
| """ | """ | ||||||
|     def __init__(self, module='__main__', defaultTest=None, |     def __init__(self, module='__main__', defaultTest=None, | ||||||
|                  argv=None, testRunner=None): |                  argv=None, testRunner=None, testLoader=defaultTestLoader): | ||||||
|         if type(module) == type(''): |         if type(module) == type(''): | ||||||
|             self.module = __import__(module) |             self.module = __import__(module) | ||||||
|             for part in string.split(module,'.')[1:]: |             for part in string.split(module,'.')[1:]: | ||||||
|  | @ -637,11 +623,12 @@ def __init__(self, module='__main__', defaultTest=None, | ||||||
|             self.module = module |             self.module = module | ||||||
|         if argv is None: |         if argv is None: | ||||||
|             argv = sys.argv |             argv = sys.argv | ||||||
|  |         self.verbosity = 1 | ||||||
|         self.defaultTest = defaultTest |         self.defaultTest = defaultTest | ||||||
|         self.testRunner = testRunner |         self.testRunner = testRunner | ||||||
|  |         self.testLoader = testLoader | ||||||
|         self.progName = os.path.basename(argv[0]) |         self.progName = os.path.basename(argv[0]) | ||||||
|         self.parseArgs(argv) |         self.parseArgs(argv) | ||||||
|         self.createTests() |  | ||||||
|         self.runTests() |         self.runTests() | ||||||
| 
 | 
 | ||||||
|     def usageExit(self, msg=None): |     def usageExit(self, msg=None): | ||||||
|  | @ -652,29 +639,34 @@ def usageExit(self, msg=None): | ||||||
|     def parseArgs(self, argv): |     def parseArgs(self, argv): | ||||||
|         import getopt |         import getopt | ||||||
|         try: |         try: | ||||||
|             options, args = getopt.getopt(argv[1:], 'hH', ['help']) |             options, args = getopt.getopt(argv[1:], 'hHvq', | ||||||
|  |                                           ['help','verbose','quiet']) | ||||||
|             opts = {} |             opts = {} | ||||||
|             for opt, value in options: |             for opt, value in options: | ||||||
|                 if opt in ('-h','-H','--help'): |                 if opt in ('-h','-H','--help'): | ||||||
|                     self.usageExit() |                     self.usageExit() | ||||||
|  |                 if opt in ('-q','--quiet'): | ||||||
|  |                     self.verbosity = 0 | ||||||
|  |                 if opt in ('-v','--verbose'): | ||||||
|  |                     self.verbosity = 2 | ||||||
|             if len(args) == 0 and self.defaultTest is None: |             if len(args) == 0 and self.defaultTest is None: | ||||||
|                 raise getopt.error, "No default test is defined." |                 self.test = self.testLoader.loadTestsFromModule(self.module) | ||||||
|  |                 return | ||||||
|             if len(args) > 0: |             if len(args) > 0: | ||||||
|                 self.testNames = args |                 self.testNames = args | ||||||
|             else: |             else: | ||||||
|                 self.testNames = (self.defaultTest,) |                 self.testNames = (self.defaultTest,) | ||||||
|  |             self.createTests() | ||||||
|         except getopt.error, msg: |         except getopt.error, msg: | ||||||
|             self.usageExit(msg) |             self.usageExit(msg) | ||||||
| 
 | 
 | ||||||
|     def createTests(self): |     def createTests(self): | ||||||
|         tests = [] |         self.test = self.testLoader.loadTestsFromNames(self.testNames, | ||||||
|         for testName in self.testNames: |                                                        self.module) | ||||||
|             tests.append(createTestInstance(testName, self.module)) |  | ||||||
|         self.test = TestSuite(tests) |  | ||||||
| 
 | 
 | ||||||
|     def runTests(self): |     def runTests(self): | ||||||
|         if self.testRunner is None: |         if self.testRunner is None: | ||||||
|             self.testRunner = TextTestRunner() |             self.testRunner = TextTestRunner(verbosity=self.verbosity) | ||||||
|         result = self.testRunner.run(self.test) |         result = self.testRunner.run(self.test) | ||||||
|         sys.exit(not result.wasSuccessful())     |         sys.exit(not result.wasSuccessful())     | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Steve Purcell
						Steve Purcell