[Zope3-checkins] SVN: zope.testing/branches/stub-testSetUp_in_layer/src/zope/testing/testrunner.py Refactor bits of testrunner.py to make it more unit testable and add some docstrings to this desert

Stuart Bishop cvs-admin at zope.org
Fri Jun 16 02:26:51 EDT 2006


Log message for revision 68685:
  Refactor bits of testrunner.py to make it more unit testable and add some docstrings to this desert

Changed:
  U   zope.testing/branches/stub-testSetUp_in_layer/src/zope/testing/testrunner.py

-=-
Modified: zope.testing/branches/stub-testSetUp_in_layer/src/zope/testing/testrunner.py
===================================================================
--- zope.testing/branches/stub-testSetUp_in_layer/src/zope/testing/testrunner.py	2006-06-16 06:22:34 UTC (rev 68684)
+++ zope.testing/branches/stub-testSetUp_in_layer/src/zope/testing/testrunner.py	2006-06-16 06:26:47 UTC (rev 68685)
@@ -253,7 +253,7 @@
 
     try:
         try:
-            failed = run_with_options(options)
+            failed = not run_with_options(options)
         except EndRun:
             failed = True
     finally:
@@ -288,8 +288,17 @@
 
     return failed
 
-def run_with_options(options):
+def run_with_options(options, found_suites=None):
+    """Find and run tests
+    
+    Passing a list of suites using the found_suites parameter will cause
+    that list of suites to be used instead of attempting to load them from
+    the filesystem. This is useful for unit testing the test runner.
 
+    Returns True if all tests passed, or False if there were any failures
+    of any kind.
+    """
+
     if options.resume_layer:
         original_stderr = sys.stderr
         sys.stderr = sys.stdout
@@ -350,7 +359,7 @@
 
     remove_stale_bytecode(options)
 
-    tests_by_layer_name = find_tests(options)
+    tests_by_layer_name = find_tests(options, found_suites)
 
     ran = 0
     failures = []
@@ -456,7 +465,7 @@
     if options.gc:
         gc.set_threshold(*old_threshold)
 
-    return bool(import_errors or failures or errors)
+    return not bool(import_errors or failures or errors)
 
 def run_tests(options, tests, name, failures, errors):
     repeat = options.repeat or 1
@@ -656,7 +665,7 @@
     if layer not in setup_layers:
         for base in layer.__bases__:
             setup_layer(base, setup_layers)
-        print "  Set up %s.%s" % (layer.__module__, layer.__name__),
+        print "  Set up %s" % name_from_layer(layer),
         t = time.time()
         layer.setUp()
         print "in %.3f seconds." % (time.time() - t)
@@ -923,6 +932,15 @@
         gather_layers(b, result)
 
 def layer_from_name(layer_name):
+    """Return the layer for the corresponding layer_name by discovering
+       and importing the necessary module if necessary.
+
+       Note that a name -> layer cache is maintained by name_from_layer
+       to allow locating layers in cases where it would otherwise be
+       impossible.
+    """
+    if _layer_name_cache.has_key(layer_name):
+        return _layer_name_cache[layer_name]
     layer_names = layer_name.split('.')
     layer_module, module_layer_name = layer_names[:-1], layer_names[-1]
     return getattr(import_name('.'.join(layer_module)), module_layer_name)
@@ -946,12 +964,34 @@
                 result.append(layer)
     return result
 
+_layer_name_cache = {}
+
 def name_from_layer(layer):
-    return layer.__module__ + '.' + layer.__name__
+    """Determine a name for the Layer using the namespace to avoid conflicts.
 
-def find_tests(options):
+    We also cache a name -> layer mapping to enable layer_from_name to work
+    in cases where the layer cannot be imported (such as layers defined
+    in doctests)
+    """
+    if layer.__module__ == '__builtin__':
+        name = layer.__name__
+    else:
+        name = layer.__module__ + '.' + layer.__name__
+    _layer_name_cache[name] = layer
+    return name
+
+def find_tests(options, found_suites=None):
+    """Creates a dictionary mapping layer name to a suite of tests to be run
+    in that layer.
+
+    Passing a list of suites using the found_suites parameter will cause
+    that list of suites to be used instead of attempting to load them from
+    the filesystem. This is useful for unit testing the test runner.
+    """
     suites = {}
-    for suite in find_suites(options):
+    if found_suites is None:
+        found_suites = find_suites(options)
+    for suite in found_suites:
         for test, layer_name in tests_from_suite(suite, options):
             suite = suites.get(layer_name)
             if not suite:
@@ -960,10 +1000,20 @@
     return suites
 
 def tests_from_suite(suite, options, dlevel=1, dlayer='unit'):
+    """Returns a sequence of (test, layer_name)
+
+    The tree of suites is recursively visited, with the most specific
+    layer taking precidence. So if a TestCase with a layer of 'foo' is
+    contained in a TestSuite with a layer of 'bar', the test case would be
+    returned with 'foo' as the layer.
+
+    Tests are also filtered out based on the test level and test selection
+    filters stored in the options.
+    """
     level = getattr(suite, 'level', dlevel)
     layer = getattr(suite, 'layer', dlayer)
     if not isinstance(layer, basestring):
-        layer = layer.__module__ + '.' + layer.__name__
+        layer = name_from_layer(layer)
 
     if isinstance(suite, unittest.TestSuite):
         for possible_suite in suite:



More information about the Zope3-Checkins mailing list