mirror of https://github.com/python/cpython.git
Updated to latest PyUnit version (1.31 in PyUnit CVS); test_support.py
changed accordingly.
This commit is contained in:
parent
2e2cded1b5
commit
5ddd1a8dcb
|
@ -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__))
|
||||||
|
|
480
Lib/unittest.py
480
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,17 +113,23 @@ 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'.
|
||||||
|
|
||||||
If the fixture may be used for many test cases, create as
|
If the fixture may be used for many test cases, create as
|
||||||
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,10 +246,26 @@ 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
|
||||||
|
|
||||||
def __exc_info(self):
|
def __exc_info(self):
|
||||||
"""Return a version of sys.exc_info() with the traceback frame
|
"""Return a version of sys.exc_info() with the traceback frame
|
||||||
minimised; usually the top level of the traceback frame is not
|
minimised; usually the top level of the traceback frame is not
|
||||||
|
@ -278,8 +320,8 @@ 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):
|
||||||
|
@ -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'
|
||||||
dir(testCaseClass))
|
sortTestMethodsUsing = cmp
|
||||||
for baseclass in testCaseClass.__bases__:
|
suiteClass = TestSuite
|
||||||
testFnNames = testFnNames + \
|
|
||||||
getTestCaseNames(baseclass, prefix, sortUsing=None)
|
|
||||||
if sortUsing:
|
|
||||||
testFnNames.sort(sortUsing)
|
|
||||||
return testFnNames
|
|
||||||
|
|
||||||
|
def loadTestsFromTestCase(self, testCaseClass):
|
||||||
|
return self.suiteClass(map(testCaseClass,
|
||||||
|
self.getTestCaseNames(testCaseClass)))
|
||||||
|
|
||||||
def makeSuite(testCaseClass, prefix='test', sortUsing=cmp):
|
def loadTestsFromModule(self, module):
|
||||||
"""Returns a TestSuite instance built from all of the test functions
|
tests = []
|
||||||
in the given test case class whose names begin with the given
|
for name in dir(module):
|
||||||
prefix. The cases are sorted by their function names
|
obj = getattr(module, name)
|
||||||
using the supplied comparison function, which defaults to 'cmp'.
|
if type(obj) == types.ClassType and issubclass(obj, TestCase):
|
||||||
"""
|
tests.append(self.loadTestsFromTestCase(obj))
|
||||||
cases = map(testCaseClass,
|
return self.suiteClass(tests)
|
||||||
getTestCaseNames(testCaseClass, prefix, sortUsing))
|
|
||||||
return TestSuite(cases)
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
def createTestInstance(name, module=None):
|
if type(obj) == types.ModuleType:
|
||||||
"""Finds tests by their name, optionally only within the given module.
|
return self.loadTestsFromModule(obj)
|
||||||
|
elif type(obj) == types.ClassType and issubclass(obj, TestCase):
|
||||||
Return the newly-constructed test, ready to run. If the name contains a ':'
|
return self.loadTestsFromTestCase(obj)
|
||||||
then the portion of the name after the colon is used to find a specific
|
elif type(obj) == types.UnboundMethodType:
|
||||||
test case within the test case class named before the colon.
|
return obj.im_class(obj.__name__)
|
||||||
|
elif callable(obj):
|
||||||
Examples:
|
test = obj()
|
||||||
findTest('examples.listtests.suite')
|
if not isinstance(test, TestCase) and \
|
||||||
-- returns result of calling 'suite'
|
not isinstance(test, TestSuite):
|
||||||
findTest('examples.listtests.ListTestCase:checkAppend')
|
raise ValueError, \
|
||||||
-- returns result of calling ListTestCase('checkAppend')
|
"calling %s returned %s, not a test" % obj,test
|
||||||
findTest('examples.listtests.ListTestCase:check-')
|
return test
|
||||||
-- returns result of calling makeSuite(ListTestCase, prefix="check")
|
|
||||||
"""
|
|
||||||
|
|
||||||
spec = string.split(name, ':')
|
|
||||||
if len(spec) > 2: raise ValueError, "illegal test name: %s" % name
|
|
||||||
if len(spec) == 1:
|
|
||||||
testName = spec[0]
|
|
||||||
caseName = None
|
|
||||||
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:
|
else:
|
||||||
test = constructor(caseName)
|
raise ValueError, "don't know how to make test from: %s" % obj
|
||||||
else:
|
|
||||||
test = constructor()
|
def loadTestsFromNames(self, names, module=None):
|
||||||
if not hasattr(test,"countTestCases"):
|
suites = []
|
||||||
raise TypeError, \
|
for name in names:
|
||||||
"object %s found with spec %s is not a test" % (test, name)
|
suites.append(self.loadTestsFromName(name, module))
|
||||||
return test
|
return self.suiteClass(suites)
|
||||||
|
|
||||||
|
def getTestCaseNames(self, testCaseClass):
|
||||||
|
testFnNames = filter(lambda n,p=self.testMethodPrefix: n[:len(p)] == p,
|
||||||
|
dir(testCaseClass))
|
||||||
|
for baseclass in testCaseClass.__bases__:
|
||||||
|
for testFnName in self.getTestCaseNames(baseclass):
|
||||||
|
if testFnName not in testFnNames: # handle overridden methods
|
||||||
|
testFnNames.append(testFnName)
|
||||||
|
if self.sortTestMethodsUsing:
|
||||||
|
testFnNames.sort(self.sortTestMethodsUsing)
|
||||||
|
return testFnNames
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
defaultTestLoader = TestLoader()
|
||||||
|
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# Patches for old functions: these functions should be considered obsolete
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
def _makeLoader(prefix, sortUsing, suiteClass=None):
|
||||||
|
loader = TestLoader()
|
||||||
|
loader.sortTestMethodsUsing = sortUsing
|
||||||
|
loader.testMethodPrefix = prefix
|
||||||
|
if suiteClass: loader.suiteClass = suiteClass
|
||||||
|
return loader
|
||||||
|
|
||||||
|
def getTestCaseNames(testCaseClass, prefix, sortUsing=cmp):
|
||||||
|
return _makeLoader(prefix, sortUsing).getTestCaseNames(testCaseClass)
|
||||||
|
|
||||||
|
def makeSuite(testCaseClass, prefix='test', sortUsing=cmp, suiteClass=TestSuite):
|
||||||
|
return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromTestCase(testCaseClass)
|
||||||
|
|
||||||
|
def findTestCases(module, prefix='test', sortUsing=cmp, suiteClass=TestSuite):
|
||||||
|
return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromModule(module)
|
||||||
|
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
@ -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 _TextTestResult(TestResult):
|
||||||
class _JUnitTextTestResult(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(" ... ")
|
||||||
self.stream.write(str(test))
|
|
||||||
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)
|
|
||||||
for line in apply(traceback.format_exception, err):
|
def printErrorList(self, flavour, errors):
|
||||||
for l in string.split(line,"\n")[:-1]:
|
for test, err in errors:
|
||||||
self.stream.writeln("\t%s" % l)
|
self.stream.writeln(self.separator1)
|
||||||
self.stream.writeln(separator1)
|
self.stream.writeln("%s: %s" % (flavour,self.getDescription(test)))
|
||||||
|
self.stream.writeln(self.separator2)
|
||||||
|
for line in apply(traceback.format_exception, err):
|
||||||
|
for l in string.split(line,"\n")[:-1]:
|
||||||
|
self.stream.writeln("%s" % l)
|
||||||
|
|
||||||
|
|
||||||
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…
Reference in New Issue