[Checkins] SVN: zope.component/branches/sylvain-zcmltestlayer/src/zope/component/test Intermediate checkin, so we have a ZCMLFileLayer and ZCMLStringLayer.
Martijn Faassen
faassen at startifact.com
Thu Jan 21 10:05:17 EST 2010
Log message for revision 108357:
Intermediate checkin, so we have a ZCMLFileLayer and ZCMLStringLayer.
Tests are coming next.
Changed:
U zope.component/branches/sylvain-zcmltestlayer/src/zope/component/testlayer.py
A zope.component/branches/sylvain-zcmltestlayer/src/zope/component/testlayer.txt
U zope.component/branches/sylvain-zcmltestlayer/src/zope/component/tests.py
-=-
Modified: zope.component/branches/sylvain-zcmltestlayer/src/zope/component/testlayer.py
===================================================================
--- zope.component/branches/sylvain-zcmltestlayer/src/zope/component/testlayer.py 2010-01-21 15:03:40 UTC (rev 108356)
+++ zope.component/branches/sylvain-zcmltestlayer/src/zope/component/testlayer.py 2010-01-21 15:05:17 UTC (rev 108357)
@@ -16,29 +16,106 @@
from zope.configuration import xmlconfig, config
from zope.testing.cleanup import cleanUp
+from zope.component.hooks import setHooks
-class ZCMLLayer(object):
- """Base layer in order to load a ZCML configuration.
+class LayerBase(object):
+ """Sane layer base class.
+
+ zope.testing implements an advanced mechanism so that layer setUp,
+ tearDown, testSetUp and testTearDown code gets called in the right
+ order. These methods are supposed to be @classmethods and should
+ not use super() as the test runner is supposed to take care of that.
+
+ In practice, this mechanism turns out not to be useful and
+ overcomplicated. It becomes difficult to pass information into
+ layers (such as a ZCML file to load), because the only way to pass
+ in information is to subclass, and subclassing these layers leads
+ to a range of interactions that is hard to reason about.
+
+ We'd rather just use Python and the super mechanism, as we know how
+ to reason about that. This base class is a hack to make this
+ possible.
+
+ The hack requires us to set __bases__, __module__ and
+ __name__. This fools zope.testing into thinking that this layer
+ instance is a class it can work with.
+
+ It'd be better if zope.testing just called a minimal API and
+ didn't try to be fancy. Fancy layer inheritance mechanisms can
+ then be implemented elsewhere if people want to. But unfortunately
+ it does implement a fancy mechanism and we need to fool it.
"""
-
+
__bases__ = ()
- def __init__(self, package, name=None, zcml_file='ftesting.zcml'):
+ def __init__(self, package, name=None):
if name is None:
name = self.__class__.__name__
self.__name__ = name
self.__module__ = package.__name__
- self.zcml_file = os.path.join(
- os.path.dirname(package.__file__), zcml_file)
- self.features = ()
def setUp(self):
- zope.component.hooks.setHooks()
+ pass
+
+ def tearDown(self):
+ pass
+
+ def testSetUp(self):
+ pass
+
+ def testTearDown(self):
+ pass
+
+class ZCMLLayerBase(LayerBase):
+ """Base class to load up some ZCML.
+ """
+ def __init__(self, package, name=None, features=None):
+ super(ZCMLLayerBase, self).__init__(package, name)
+ self.features = features or []
+
+ def setUp(self):
+ setHooks()
context = config.ConfigurationMachine()
xmlconfig.registerCommonDirectives(context)
for feature in self.features:
context.provideFeature(feature)
- context = xmlconfig.file(self.zcml_file, context=context, execute=True)
+ self._load_zcml(context)
def tearDown(self):
cleanUp()
+
+ def _load_zcml(self, context):
+ raise NotImplementedError
+
+class ZCMLStringLayer(ZCMLLayerBase):
+ """This layer can be used to run tests with a ZCML string loaded.
+
+ The ZCML string is assumed to include sufficient (meta)configuration
+ so that it can be interpreted itself. I.e. to create a ZCMLLayer
+ based on another ZCMLLayer's ZCML, just use a ZCML include
+ statement in your own ZCML to load it.
+ """
+ def __init__(self, package, name=None, zcml_string=None,
+ features=None):
+ super(ZCMLStringLayer, self).__init__(package, name, features)
+ self.zcml_string = zcml_string
+
+ def _load_zcml(self, context):
+ xmlconfig.string(self.zcml_string, context=context, execute=True)
+
+class ZCMLFileLayer(ZCMLLayerBase):
+ """This layer can be used to run tests with a ZCML file loaded.
+
+ The ZCML file is assumed to include sufficient (meta)configuration
+ so that it can be interpreted itself. I.e. to create a ZCMLLayer
+ based on another ZCMLLayer's ZCML, just use a ZCML include
+ statement in your own ZCML to load it.
+ """
+ def __init__(self, package, name=None, zcml_file='ftesting.zcml',
+ features=None):
+ super(ZCMLFileLayer, self).__init__(package, name, features)
+ self.zcml_file = os.path.join(os.path.dirname(package.__file__),
+ zcml_file)
+
+ def _load_zcml(self, context):
+ xmlconfig.file(self.zcml_file, context=context, execute=True)
Added: zope.component/branches/sylvain-zcmltestlayer/src/zope/component/testlayer.txt
===================================================================
--- zope.component/branches/sylvain-zcmltestlayer/src/zope/component/testlayer.txt (rev 0)
+++ zope.component/branches/sylvain-zcmltestlayer/src/zope/component/testlayer.txt 2010-01-21 15:05:17 UTC (rev 108357)
@@ -0,0 +1,70 @@
+Layers
+======
+
+zope.component.testlayer defines two things:
+
+* a LayerBase that makes it easier and saner to use zope.testing's
+ test layers.
+
+* a ZCMLLayer which lets you implement a layer that loads up some
+ ZCML.
+
+LayerBase
+---------
+
+We check whether our LayerBase can be used to create layers of our
+own. We do this simply by subclassing::
+
+ >>> from zope.component.testlayer import LayerBase
+ >>> class OurLayer(LayerBase):
+ ... def setUp(self):
+ ... super(OurLayer, self).setUp()
+ ... print "setUp called"
+ ... def tearDown(self):
+ ... super(OurLayer, self).tearDown()
+ ... print "tearDown called"
+ ... def testSetUp(self):
+ ... super(OurLayer, self).testSetUp()
+ ... print "testSetUp called"
+ ... def testTearDown(self):
+ ... super(OurLayer, self).testTearDown()
+ ... print "testTearDown called"
+
+Note that if we wanted to ensure that the methods of the superclass
+were called we have to use super(). In this case we actually wouldn't
+need to, as these methods do nothing at all, but we just ensure that
+they are there in the first place.
+
+Let's instantiate our layer. We need to supply it with the package the
+layer is defined in::
+
+ >>> import zope.component
+ >>> layer = OurLayer(zope.component)
+
+Now we run some tests with this layer::
+
+ >>> import unittest
+ >>> class TestCase(unittest.TestCase):
+ ... layer = layer
+ ...
+ ... def testFoo(self):
+ ... print "testFoo"
+ >>> suite = unittest.TestSuite()
+ >>> suite.addTest(unittest.makeSuite(TestCase))
+ >>> from zope.testing.testrunner.runner import Runner
+ >>> runner = Runner(found_suites=[suite])
+ >>> succeeded = runner.run()
+ Running zope.component.OurLayer tests:
+ Set up zope.component.OurLayer setUp called
+ in ... seconds.
+ testSetUp called
+ testFoo
+ testTearDown called
+ Ran 1 tests with 0 failures and 0 errors in ... seconds.
+ Tearing down left over layers:
+ Tear down zope.component.OurLayer tearDown called
+ in ... seconds.
+
+ZCMLLayer
+---------
+
Modified: zope.component/branches/sylvain-zcmltestlayer/src/zope/component/tests.py
===================================================================
--- zope.component/branches/sylvain-zcmltestlayer/src/zope/component/tests.py 2010-01-21 15:03:40 UTC (rev 108356)
+++ zope.component/branches/sylvain-zcmltestlayer/src/zope/component/tests.py 2010-01-21 15:05:17 UTC (rev 108357)
@@ -1706,6 +1706,10 @@
setUp=setUp, tearDown=tearDown),
doctest.DocFileSuite('zcml.txt', checker=checker,
setUp=setUp, tearDown=tearDown),
+ doctest.DocFileSuite('testlayer.txt',
+ optionflags=(doctest.ELLIPSIS +
+ doctest.NORMALIZE_WHITESPACE +
+ doctest.REPORT_NDIFF)),
zcml_conditional,
hooks_conditional,
unittest.makeSuite(StandaloneTests),
More information about the checkins
mailing list