[Zope-Checkins] CVS: Zope - test.py:1.2.2.3

Stefan H. Holek stefan at epy.co.at
Thu Mar 25 17:27:19 EST 2004


Update of /cvs-repository/Zope
In directory cvs.zope.org:/tmp/cvs-serv21055

Modified Files:
      Tag: Zope-2_7-branch
	test.py 
Log Message:
Synced changes from HEAD to 2_7-branch.


=== Zope/test.py 1.2.2.2 => 1.2.2.3 ===
--- Zope/test.py:1.2.2.2	Thu Mar 18 08:24:01 2004
+++ Zope/test.py	Thu Mar 25 17:27:17 2004
@@ -16,13 +16,28 @@
 """
 test.py [-abcdDfgGhLmprtTuv] [modfilter [testfilter]]
 
-Test harness.
+Find and run tests written using the unittest module.
+
+The test runner searches for Python modules that contain test suites.
+It collects those suites, and runs the tests.  There are many options
+for controlling how the tests are run.  There are options for using
+the debugger, reporting code coverage, and checking for refcount problems.
+
+The test runner uses the following rules for finding tests to run.  It
+searches for packages and modules that contain "tests" as a component
+of the name, e.g. "frob.tests.nitz" matches this rule because tests is
+a sub-package of frob.  Within each "tests" package, it looks for
+modules that begin with the name "test."  For each test module, it
+imports the module and calls the test_suite() method, which must
+return a unittest TestSuite object.  (If a package contains a file
+named .testinfo, it will not be searched for tests.  Really.)
 
 -a level
 --all
-    Run the tests at the given level.  Any test at a level at or below this is
-    run, any test at a level above this is not run.  Level 0 runs all tests.
-    The default is to run tests at level 1.  --all is a shortcut for -a 0.
+    Run the tests at the given level.  Any test at a level at or below
+    this is run, any test at a level above this is not run.  Level 0
+    runs all tests.  The default is to run tests at level 1.  --all is
+    a shortcut for -a 0.
 
 -b
     Run "python setup.py build_ext -i" before running tests, where
@@ -54,10 +69,10 @@
     Run functional tests instead of unit tests.
 
 -g threshold
-    Set the garbage collector generation0 threshold.  This can be used to
-    stress memory and gc correctness.  Some crashes are only reproducible when
-    the threshold is set to 1 (agressive garbage collection).  Do "-g 0" to
-    disable garbage collection altogether.
+    Set the garbage collector generation0 threshold.  This can be used
+    to stress memory and gc correctness.  Some crashes are only
+    reproducible when the threshold is set to 1 (agressive garbage
+    collection).  Do "-g 0" to disable garbage collection altogether.
 
 -G gc_option
     Set the garbage collection debugging flags.  The argument must be one
@@ -88,26 +103,26 @@
     This requires that Python was built --with-pydebug.
 
 -T
-    Use the trace module from Python for code coverage.  XXX This only works
-    if trace.py is explicitly added to PYTHONPATH.  The current utility writes
-    coverage files to a directory named `coverage' that is parallel to
-    `build'.  It also prints a summary to stdout.
+    Use the trace module from Python for code coverage.  XXX This only
+    works if trace.py is explicitly added to PYTHONPATH.  The current
+    utility writes coverage files to a directory named `coverage' that
+    is parallel to `build'.  It also prints a summary to stdout.
 
 -v
-    Verbose output.  With one -v, unittest prints a dot (".") for each test
-    run.  With -vv, unittest prints the name of each test (for some definition
-    of "name" ...).  With no -v, unittest is silent until the end of the run,
-    except when errors occur.
+    Verbose output.  With one -v, unittest prints a dot (".") for each
+    test run.  With -vv, unittest prints the name of each test (for
+    some definition of "name" ...).  With no -v, unittest is silent
+    until the end of the run, except when errors occur.
 
 -u
 -m
-    Use the PyUnit GUI instead of output to the command line.  The GUI imports
-    tests on its own, taking care to reload all dependencies on each run.  The
-    debug (-d), verbose (-v), and Loop (-L) options will be ignored.  The
-    testfilter filter is also not applied.
+    Use the PyUnit GUI instead of output to the command line.  The GUI
+    imports tests on its own, taking care to reload all dependencies
+    on each run.  The debug (-d), verbose (-v), and Loop (-L) options
+    will be ignored.  The testfilter filter is also not applied.
 
-    -m starts the gui minimized.  Double-clicking the progress bar will start
-    the import and run all tests.
+    -m starts the gui minimized.  Double-clicking the progress bar
+    will start the import and run all tests.
 
 
 modfilter
@@ -183,7 +198,7 @@
         self._debug = debug
         self._progress = progress
         self._progressWithNames = False
-        self._count = count
+        self.count = count
         self._testtimes = {}
         if progress and verbosity == 1:
             self.dots = False
@@ -240,9 +255,9 @@
     def startTest(self, test):
         if self._progress:
             self.stream.write("\r%4d" % (self.testsRun + 1))
-            if self._count:
-                self.stream.write("/%d (%5.1f%%)" % (self._count,
-                                  (self.testsRun + 1) * 100.0 / self._count))
+            if self.count:
+                self.stream.write("/%d (%5.1f%%)" % (self.count,
+                                  (self.testsRun + 1) * 100.0 / self.count))
             if self.showAll:
                 self.stream.write(": ")
             elif self._progressWithNames:
@@ -315,14 +330,20 @@
         self.__super_init(**kwarg)
         self._debug = debug
         self._progress = progress
+        # Create the test result here, so that we can add errors if
+        # the test suite search process has problems.  The count
+        # attribute must be set in run(), because we won't know the
+        # count until all test suites have been found.
+        self.result = ImmediateTestResult(
+            self.stream, self.descriptions, self.verbosity, debug=self._debug,
+            progress=self._progress)
 
     def _makeResult(self):
-        return ImmediateTestResult(self.stream, self.descriptions,
-                                   self.verbosity, debug=self._debug,
-                                   count=self._count, progress=self._progress)
+        # Needed base class run method.
+        return self.result
 
     def run(self, test):
-        self._count = test.countTestCases()
+        self.result.count = test.countTestCases()
         return unittest.TextTestRunner.run(self, test)
 
 # setup list of directories to put on the path
@@ -392,6 +413,12 @@
 
     def visit(self, rx, dir, files):
         if os.path.split(dir)[1] != self.dirname:
+            # Allow tests module rather than package.
+            if "tests.py" in files:
+                path = os.path.join(dir, "tests.py")
+                if match(rx, path):
+                    self.files.append(path)
+                    return 
             return
         if not self.is_package(dir):
             return
@@ -439,22 +466,32 @@
         mod = getattr(mod, part)
     return mod
 
-def get_suite(file):
+class PseudoTestCase:
+    """Minimal test case objects to create error reports.
+
+    If test.py finds something that looks like it should be a test but
+    can't load it or find its test suite, it will report an error
+    using a PseudoTestCase.
+    """
+
+    def __init__(self, name, descr=None):
+        self.name = name
+        self.descr = descr
+
+    def shortDescription(self):
+        return self.descr
+
+    def __str__(self):
+        return "Invalid Test (%s)" % self.name
+
+def get_suite(file, result):
     modname = finder.module_from_path(file)
     try:
         mod = package_import(modname)
-    except ImportError, err:
-        # print traceback
-        print "Error importing %s\n%s" % (modname, err)
-        if debug:
-            raise
-        return None
-    try:
-        suite_func = mod.test_suite
+        return mod.test_suite()
     except AttributeError:
-        print "No test_suite() in %s" % file
+        result.addError(PseudoTestCase(modname), sys.exc_info())
         return None
-    return suite_func()
 
 def filter_testcases(s, rx):
     new = unittest.TestSuite()
@@ -534,7 +571,7 @@
                                  progress=progress)
     suite = unittest.TestSuite()
     for file in files:
-        s = get_suite(file)
+        s = get_suite(file, runner.result)
         # See if the levels match
         dolevel = (level == 0) or level >= getattr(s, "level", 0)
         if s is not None and dolevel:
@@ -568,11 +605,8 @@
     if not keepStaleBytecode:
         os.path.walk(os.curdir, remove_stale_bytecode, None)
 
-    
     global pathinit
-
-
-
+    
     # Get the log.ini file from the current directory instead of possibly
     # buried in the build directory.  XXX This isn't perfect because if
     # log.ini specifies a log file, it'll be relative to the build directory.
@@ -581,7 +615,6 @@
 
     # Initialize the path and cwd
     pathinit = PathInit(build, libdir)
-
 
     # Initialize the logging module.
     import logging.config




More information about the Zope-Checkins mailing list