[Zope3-checkins] SVN: zope.testing/branches/test-checkers/src/zope/testing/ Add an example test checker and a useful base class.

Marius Gedminas marius at pov.lt
Sat Jan 20 13:53:06 EST 2007


Log message for revision 72150:
  Add an example test checker and a useful base class.
  
  What's missing?  Unit tests!
  
  

Changed:
  A   zope.testing/branches/test-checkers/src/zope/testing/checkers.py
  U   zope.testing/branches/test-checkers/src/zope/testing/loggingsupport.py

-=-
Added: zope.testing/branches/test-checkers/src/zope/testing/checkers.py
===================================================================
--- zope.testing/branches/test-checkers/src/zope/testing/checkers.py	2007-01-20 18:51:12 UTC (rev 72149)
+++ zope.testing/branches/test-checkers/src/zope/testing/checkers.py	2007-01-20 18:53:05 UTC (rev 72150)
@@ -0,0 +1,76 @@
+##############################################################################
+#
+# Copyright (c) 2007 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Support for test checkers
+
+Test checkers are used to identify tests that do not clean up after themselves.
+"""
+
+import sys
+
+
+class AbstractTestChecker(object):
+    """A useful base class for test checkers.
+
+    You are not required to subclass it (this is Python after all!), but you
+    may find it convenient.
+
+    Subclasses of AbstractTestChecker take a snapshot of some global state
+    before each test is run, then take another snapshot after the test is
+    finished, and compare those snapshots.  If there are differences,
+    a warning is printed to stderr.
+    """
+
+    what = 'something' # change this in subclasses
+
+    def startTest(self, test):
+        self.old_state = self.takeSnapshot()
+
+    def stopTest(self, test):
+        new_state = self.takeSnapshot()
+        if self.old_state != new_state:
+            self.warn("%s changed %s" % (test, self.what))
+            self.showDifferences(self.old_state, new_state)
+        del self.old_state
+
+    def startLayer(self, layer):
+        self.old_layer_state = self.takeSnapshot()
+
+    def stopLayer(self, layer):
+        new_layer_state = self.takeSnapshot()
+        if self.old_layer_state != new_layer_state:
+            self.warn("%s changed %s" % (layer, self.what))
+            self.showDifferences(self.old_layer_state, new_layer_state)
+        del self.old_layerstate
+
+    def takeSnapshot(self):
+        """Take a snapshot of the global state.
+
+        Returns something that can be compared.
+        """
+        raise NotImplementedError('override in subclasses')
+
+    def showDifferences(self, old_state, new_state):
+        """Show the differences between old and new state.
+
+        Does nothing by default, but can be overridden.
+        """
+        pass
+
+    def warn(self, msg):
+        """Print a message to stderr."""
+        # It is a good idea to print a newline at the beginning, because the
+        # test runner may be doing fancy formatting and we do not want the
+        # message to appear somewhere in the middle of another line.
+        print >> sys.stderr, "\n" + msg
+


Property changes on: zope.testing/branches/test-checkers/src/zope/testing/checkers.py
___________________________________________________________________
Name: svn:keywords
   + Id

Modified: zope.testing/branches/test-checkers/src/zope/testing/loggingsupport.py
===================================================================
--- zope.testing/branches/test-checkers/src/zope/testing/loggingsupport.py	2007-01-20 18:51:12 UTC (rev 72149)
+++ zope.testing/branches/test-checkers/src/zope/testing/loggingsupport.py	2007-01-20 18:53:05 UTC (rev 72150)
@@ -73,6 +73,9 @@
 
 import logging
 
+from zope.testing.checkers import AbstractTestChecker
+
+
 class Handler(logging.Handler):
 
     def __init__(self, *names, **kw):
@@ -122,3 +125,49 @@
     def __init__(self, *names, **kw):
         Handler.__init__(self, *names, **kw)
         self.install()
+
+
+class LoggingTestChecker(AbstractTestChecker):
+    """Test checker that looks for tests who register loggers and leave them."""
+
+    what = 'the logging framework'
+
+    def takeSnapshot(self):
+        state = {}
+        for name, logger in logging.root.manager.loggerDict.items():
+            if isinstance(logger, logging.PlaceHolder):
+                continue
+            if (logger.propagate and not logger.handlers and not
+                logger.disabled and logger.level == logging.NOTSET):
+                # This logger is completely transparent.  Ignore it.
+                # This is particularly important because the logging module has
+                # no way to remove a logger other than making it transparent.
+                continue
+            # Remember the values of the interesting attributes, so that we
+            # notice changes and not just the appearance of new loggers.
+            state[name] = {'handlers': logger.handlers,
+                           'propagate': logger.propagate,
+                           'level': logger.level,
+                           'disabled': logger.disabled}
+        return state
+
+    def showDifferences(self, old_state, new_state):
+        for name in sorted(set(old_state) | set(new_state)):
+            if name in old_state and name not in new_state:
+                self.warn("  logger %s disappeared" % name)
+            elif name in new_state and name not in old_state:
+                self.warn("  new logger: %s" % name)
+            else:
+                attrs = [attr for attr in sorted(new_state[name])
+                         if old_state[name][attr] != new_state[name][attr]]
+                self.warn("  logger %s changed: %s" % (name, ', '.join(attrs)))
+
+
+def test_checkers():
+    """Return a list of checkers.
+
+    The checkers can be enabled by running the test runner with
+    --checkers zope.testing.loggingsupport
+    """
+    return [LoggingTestChecker()]
+



More information about the Zope3-Checkins mailing list