[Zope-Checkins] CVS: Zope/utilities - testrunner.py:1.33
Fred L. Drake, Jr.
fred@zope.com
Thu, 30 Jan 2003 16:19:54 -0500
Update of /cvs-repository/Zope/utilities
In directory cvs.zope.org:/tmp/cvs-serv1042
Modified Files:
testrunner.py
Log Message:
Lots of really small changes.
=== Zope/utilities/testrunner.py 1.32 => 1.33 ===
--- Zope/utilities/testrunner.py:1.32 Thu Jan 30 14:24:00 2003
+++ Zope/utilities/testrunner.py Thu Jan 30 16:19:51 2003
@@ -1,9 +1,9 @@
+#! /usr/bin/env python2.2
"""testrunner - a Zope test suite utility.
-The testrunner utility is used to execute PyUnit test suites. You can find
-more information on PyUnit at http://pyunit.sourceforge.net. This utility
-should be run from the root of your Zope installation. It will set up the
-correct python path environment based on your installation directory so that
+The testrunner utility is used to execute PyUnit test suites. This utility
+should be run from the root of your Zope source directory. It will set up the
+correct python path environment based on your source directory so that
test suites can import Zope modules in a way that is fairly independent of
the location of the test suite. It does *not* import the Zope package, so
a test thats depend on dynamic aspects of the Zope environment (such as
@@ -13,14 +13,18 @@
Testrunner will look for and execute test suites that follow some simple
conventions. Test modules should have a name prefixed with 'test', such as
'testMyModule.py', and test modules are expected to define a module function
-named 'test_suite' that returns a PyUnit TestSuite object. By convention,
-we put test suites in 'tests' subdirectories of the packages they test.
+named 'test_suite' that returns a TestSuite object. By convention,
+we put test modules in a 'tests' sub-package of the package they test.
Testrunner is used to run all checked in test suites before (final) releases
are made, and can be used to quickly run a particular suite or all suites in
a particular directory."""
-import sys, os, imp, string, getopt, traceback
+import getopt
+import imp
+import os
+import sys
+import traceback
import unittest
VERBOSE = 2
@@ -28,30 +32,31 @@
class TestRunner:
"""Test suite runner"""
- def __init__(self, basepath, verbosity=VERBOSE, results=[], mega_suite=0):
- # initialize python path
- self.basepath=path=basepath
+ def __init__(self, path, verbosity, mega_suite):
+ self.basepath = path
self.verbosity = verbosity
- self.results = results
+ self.results = []
self.mega_suite = mega_suite
- pjoin=os.path.join
+ # initialize python path
+ pjoin = os.path.join
if sys.platform == 'win32':
- sys.path.insert(0, pjoin(path, 'lib/python'))
- sys.path.insert(1, pjoin(path, 'bin/lib'))
- sys.path.insert(2, pjoin(path, 'bin/lib/plat-win'))
- sys.path.insert(3, pjoin(path, 'bin/lib/win32'))
- sys.path.insert(4, pjoin(path, 'bin/lib/win32/lib'))
- sys.path.insert(5, path)
+ newpaths = [pjoin(path, 'lib', 'python'),
+ pjoin(path, 'bin', 'lib'),
+ pjoin(path, 'bin', 'lib', 'plat-win'),
+ pjoin(path, 'bin', 'lib', 'win32'),
+ pjoin(path, 'bin', 'lib', 'win32', 'lib'),
+ path]
else:
- sys.path.insert(0, pjoin(path, 'lib/python'))
- sys.path.insert(1, path)
+ newpaths = [pjoin(path, 'lib', 'python'),
+ path]
+ sys.path[:0] = newpaths
def getSuiteFromFile(self, filepath):
if not os.path.isfile(filepath):
raise ValueError, '%s is not a file' % filepath
- path, filename=os.path.split(filepath)
- name, ext=os.path.splitext(filename)
- file, pathname, desc=imp.find_module(name, [path])
+ path, filename = os.path.split(filepath)
+ name, ext = os.path.splitext(filename)
+ file, pathname, desc = imp.find_module(name, [path])
saved_syspath = sys.path[:]
module = None
try:
@@ -64,7 +69,7 @@
(tb_t, tb_v, tb_tb) = sys.exc_info()
self.report("Module %s failed to load\n%s: %s" % (pathname,
tb_t, tb_v))
- self.report(string.join(traceback.format_tb(tb_tb)) + '\n')
+ self.report(''.join(traceback.format_tb(tb_tb)) + '\n')
del tb_tb
finally:
file.close()
@@ -75,76 +80,77 @@
return None
return function()
- def smellsLikeATest(self, filepath, find=string.find):
+ def smellsLikeATest(self, filepath):
path, name = os.path.split(filepath)
fname, ext = os.path.splitext(name)
- if name[:4]=='test' and name[-3:]=='.py' and \
- name != 'testrunner.py':
-
- file=open(filepath, 'r')
- lines=file.readlines()
+ if ( name[:4] == 'test'
+ and name[-3:] == '.py'
+ and name != 'testrunner.py'):
+ file = open(filepath, 'r')
+ lines = file.readlines()
file.close()
for line in lines:
- if (find(line, 'def test_suite(') > -1) or \
- (find(line, 'framework(') > -1):
- return 1
- return 0
+ if (line.find('def test_suite(') > -1) or \
+ (line.find('framework(') > -1):
+ return True
+ return False
def runSuite(self, suite):
if suite:
- runner=unittest.TextTestRunner(stream=sys.stderr,
- verbosity=self.verbosity)
+ runner = self.getTestRunner()
self.results.append(runner.run(suite))
else:
- self.report('No suitable tests found')
+ self.report('No suitable tests found')
+
+ _runner = None
+
+ def getTestRunner(self):
+ if self._runner is None:
+ self._runner = self.createTestRunner()
+ return self._runner
+
+ def createTestRunner(self):
+ return unittest.TextTestRunner(stream=sys.stderr,
+ verbosity=self.verbosity)
def report(self, message):
- sys.stderr.write( '%s\n' % message )
+ print >>sys.stderr, message
def runAllTests(self):
"""Run all tests found in the current working directory and
all subdirectories."""
self.runPath(self.basepath)
- def listTestableNames( self, pathname ):
- """
- Return a list of the names to be traversed to build tests.
- """
+ def listTestableNames(self, pathname):
+ """Return a list of the names to be traversed to build tests."""
names = os.listdir(pathname)
if "build" in names:
# Don't recurse into build directories created by setup.py
names.remove("build")
if '.testinfo' in names: # allow local control
- f = open( os.path.join( pathname, '.testinfo' ) )
- lines = filter( None, f.readlines() )
- lines = map( lambda x: x[-1]=='\n' and x[:-1] or x, lines )
- names = filter( lambda x: x and x[0] != '#', lines )
+ f = open(os.path.join(pathname, '.testinfo'))
+ lines = filter(None, f.readlines())
+ lines = map(lambda x: x[-1]=='\n' and x[:-1] or x, lines)
+ names = filter(lambda x: x and x[0] != '#', lines)
f.close()
return names
- def extractSuite( self, pathname ):
- """
- Extract and return the appropriate test suite.
- """
- if os.path.isdir( pathname ):
-
+ def extractSuite(self, pathname):
+ """Extract and return the appropriate test suite."""
+ if os.path.isdir(pathname):
suite = unittest.TestSuite()
-
- for name in self.listTestableNames( pathname ):
-
- fullpath = os.path.join( pathname, name )
- sub_suite = self.extractSuite( fullpath )
+ for name in self.listTestableNames(pathname):
+ fullpath = os.path.join(pathname, name)
+ sub_suite = self.extractSuite(fullpath)
if sub_suite:
- suite.addTest( sub_suite )
-
+ suite.addTest(sub_suite)
return suite.countTestCases() and suite or None
- elif self.smellsLikeATest( pathname ):
-
+ elif self.smellsLikeATest(pathname):
+ dirname, name = os.path.split(pathname)
working_dir = os.getcwd()
try:
- dirname, name = os.path.split(pathname)
if dirname:
os.chdir(dirname)
try:
@@ -159,11 +165,10 @@
suite = None
finally:
os.chdir(working_dir)
-
return suite
- else: # no test there!
-
+ else:
+ # no test there!
return None
def runPath(self, pathname):
@@ -173,11 +178,11 @@
pathname = os.path.join(self.basepath, pathname)
if self.mega_suite:
- suite = self.extractSuite( pathname )
- self.runSuite( suite )
+ suite = self.extractSuite(pathname)
+ self.runSuite(suite)
else:
for name in self.listTestableNames(pathname):
- fullpath=os.path.join(pathname, name)
+ fullpath = os.path.join(pathname, name)
if os.path.isdir(fullpath):
self.runPath(fullpath)
elif self.smellsLikeATest(fullpath):
@@ -189,22 +194,22 @@
dirname, name = os.path.split(filename)
if dirname:
if self.verbosity > 2:
- sys.stderr.write('*** Changing directory to: %s\n' % dirname)
+ print >>sys.stderr, '*** Changing directory to:', dirname
os.chdir(dirname)
self.report('Running: %s' % filename)
try:
- suite=self.getSuiteFromFile(name)
+ suite = self.getSuiteFromFile(name)
except KeyboardInterrupt:
raise
except:
traceback.print_exc()
- suite=None
+ suite = None
if suite is not None:
self.runSuite(suite)
else:
self.report('No test suite found in file:\n%s\n' % filename)
if self.verbosity > 2:
- sys.stderr.write('*** Restoring directory to: %s\n' % working_dir)
+ print >>sys.stderr, '*** Restoring directory to:', working_dir
os.chdir(working_dir)
def remove_stale_bytecode(arg, dirname, names):
@@ -218,8 +223,7 @@
os.unlink(fullname)
def main(args):
-
- usage_msg="""Usage: python testrunner.py options
+ usage_msg = """Usage: python testrunner.py options
If run without options, testrunner will display this usage
message. If you want to run all test suites found in all
@@ -229,41 +233,33 @@
options:
-a
-
Run all tests found in all subdirectories of the current
working directory.
-m
-
Run all tests in a single, giant suite (consolidates error
reporting). [default]
-M
-
Run each test file's suite separately (noisier output, may
help in isolating global effects later).
-p
-
Add 'lib/python' to the Python search path. [default]
-P
-
*Don't* add 'lib/python' to the Python search path.
-d dirpath
-
Run all tests found in the directory specified by dirpath,
and recursively in all its subdirectories. The dirpath
should be a full system path.
-f filepath
-
Run the test suite found in the file specified. The filepath
should be a fully qualified path to the file to be run.
-v level
-
Set the Verbosity level to level. Newer versions of
unittest.py allow more options than older ones. Allowed
values are:
@@ -273,7 +269,6 @@
2 - Verbose (default - produces a line of output for each test)
-q
-
Run tests without producing verbose output. The tests are
normally run in verbose mode, which produces a line of
output for each test that includes the name of the test and
@@ -281,67 +276,62 @@
running with -v1.
-o filename
-
Output test results to the specified file rather than
to stderr.
-h
-
Display usage information.
"""
- pathname=None
- filename=None
- test_all=None
+ pathname = None
+ filename = None
+ test_all = False
verbosity = VERBOSE
- mega_suite = 1
- set_python_path = 1
+ mega_suite = True
+ set_python_path = True
- options, arg=getopt.getopt(args, 'amPhd:f:v:qMo:')
+ options, arg = getopt.getopt(args, 'amPhd:f:v:qMo:')
if not options:
err_exit(usage_msg)
for name, value in options:
- name=name[1:]
- if name == 'a':
- test_all=1
- elif name == 'm':
- mega_suite = 1
- elif name == 'M':
- mega_suite = 0
- elif name == 'p':
- set_python_path = 1
- elif name == 'P':
- set_python_path = 0
- elif name == 'd':
- pathname=string.strip(value)
- elif name == 'f':
- filename=string.strip(value)
- elif name == 'h':
+ if name == '-a':
+ test_all = True
+ elif name == '-m':
+ mega_suite = True
+ elif name == '-M':
+ mega_suite = False
+ elif name == '-p':
+ set_python_path = True
+ elif name == '-P':
+ set_python_path = False
+ elif name == '-d':
+ pathname = value.strip()
+ elif name == '-f':
+ filename = value.strip()
+ elif name == '-h':
err_exit(usage_msg, 0)
- elif name == 'v':
+ elif name == '-v':
verbosity = int(value)
- elif name == 'q':
+ elif name == '-q':
verbosity = 1
- elif name == 'o':
- f = open(value,'w')
+ elif name == '-o':
+ f = open(value, 'w')
sys.stderr = f
else:
err_exit(usage_msg)
os.path.walk(os.curdir, remove_stale_bytecode, None)
- testrunner = TestRunner( os.getcwd()
- , verbosity=verbosity
- , mega_suite=mega_suite)
+ testrunner = TestRunner(os.getcwd(), verbosity, mega_suite)
if set_python_path:
script = sys.argv[0]
- script_dir = os.path.split( os.path.abspath( script ) )[0]
- zope_dir = os.path.abspath( os.path.join( script_dir, '..' ) )
- sw_home = os.path.join( zope_dir, 'lib', 'python' )
+ script_dir = os.path.dirname(os.path.abspath(script))
+ zope_dir = os.path.dirname(script_dir)
+ sw_home = os.path.join(zope_dir, 'lib', 'python')
if verbosity > 1:
- testrunner.report( "Adding %s to sys.path." % sw_home )
- sys.path.insert( 0, sw_home )
+ testrunner.report("Adding %s to sys.path." % sw_home)
+ sys.path.insert(0, sw_home)
os.environ['SOFTWARE_HOME'] = sw_home
try:
@@ -358,7 +348,6 @@
elif filename:
testrunner.runFile(filename)
-
## Report overall errors / failures if there were any
fails = reduce(lambda x, y: x + len(y.failures), testrunner.results, 0)
errs = reduce(lambda x, y: x + len(y.errors), testrunner.results, 0)
@@ -368,7 +357,8 @@
if fails:
msg += "total failures=%d" % fails
if errs:
- if fails: msg += ", "
+ if fails:
+ msg += ", "
msg += "total errors=%d" % errs
msg += ")"
err_exit(msg, 1)