[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