[Checkins] SVN: zope.component/trunk/src/zope/component/test merge -r 108354:108362 svn+ssh://svn.zope.org/repos/main/zope.component/branches/sylvain-zcmltestlayer
Jan-Wijbrand Kolman
janwijbrand at gmail.com
Thu Jan 21 12:31:44 EST 2010
Log message for revision 108364:
merge -r 108354:108362 svn+ssh://svn.zope.org/repos/main/zope.component/branches/sylvain-zcmltestlayer
Changed:
U zope.component/trunk/src/zope/component/testfiles/components.py
A zope.component/trunk/src/zope/component/testfiles/testlayer.zcml
A zope.component/trunk/src/zope/component/testlayer.py
A zope.component/trunk/src/zope/component/testlayer.txt
U zope.component/trunk/src/zope/component/tests.py
-=-
Modified: zope.component/trunk/src/zope/component/testfiles/components.py
===================================================================
--- zope.component/trunk/src/zope/component/testfiles/components.py 2010-01-21 16:48:33 UTC (rev 108363)
+++ zope.component/trunk/src/zope/component/testfiles/components.py 2010-01-21 17:31:43 UTC (rev 108364)
@@ -25,6 +25,12 @@
class IApp(IAppb):
pass
+class IApp2(IAppb):
+ pass
+
+class IApp3(IAppb):
+ pass
+
class IContent(Interface): pass
class Content(object):
@@ -41,4 +47,14 @@
a = 1
def f(): pass
+class Comp2(object):
+ def __init__(self, context):
+ self.context = context
+
+class Comp3(object):
+ def __init__(self, context):
+ self.context = context
+
comp = Comp()
+
+content = Content()
Copied: zope.component/trunk/src/zope/component/testfiles/testlayer.zcml (from rev 108362, zope.component/branches/sylvain-zcmltestlayer/src/zope/component/testfiles/testlayer.zcml)
===================================================================
--- zope.component/trunk/src/zope/component/testfiles/testlayer.zcml (rev 0)
+++ zope.component/trunk/src/zope/component/testfiles/testlayer.zcml 2010-01-21 17:31:43 UTC (rev 108364)
@@ -0,0 +1,9 @@
+<configure xmlns="http://namespaces.zope.org/zope">
+ <include package="zope.component" file="meta.zcml" />
+
+ <adapter
+ factory="zope.component.testfiles.components.Comp2"
+ provides="zope.component.testfiles.components.IApp2"
+ for="zope.component.testfiles.components.IContent" />
+
+</configure>
Copied: zope.component/trunk/src/zope/component/testlayer.py (from rev 108362, zope.component/branches/sylvain-zcmltestlayer/src/zope/component/testlayer.py)
===================================================================
--- zope.component/trunk/src/zope/component/testlayer.py (rev 0)
+++ zope.component/trunk/src/zope/component/testlayer.py 2010-01-21 17:31:43 UTC (rev 108364)
@@ -0,0 +1,105 @@
+##############################################################################
+#
+# Copyright (c) 2010 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.
+#
+##############################################################################
+
+import os
+
+from zope.configuration import xmlconfig, config
+from zope.testing.cleanup import cleanUp
+from zope.component.hooks import setHooks
+
+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):
+ if name is None:
+ name = self.__class__.__name__
+ self.__name__ = name
+ self.__module__ = package.__name__
+
+ def setUp(self):
+ 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)
+ self.context = self._load_zcml(context)
+
+ def tearDown(self):
+ cleanUp()
+
+ def _load_zcml(self, context):
+ raise NotImplementedError
+
+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, zcml_file='ftesting.zcml',
+ name=None, 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):
+ return xmlconfig.file(self.zcml_file, context=context, execute=True)
Copied: zope.component/trunk/src/zope/component/testlayer.txt (from rev 108362, zope.component/branches/sylvain-zcmltestlayer/src/zope/component/testlayer.txt)
===================================================================
--- zope.component/trunk/src/zope/component/testlayer.txt (rev 0)
+++ zope.component/trunk/src/zope/component/testlayer.txt 2010-01-21 17:31:43 UTC (rev 108364)
@@ -0,0 +1,100 @@
+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
+---------
+
+We now want a layer that loads up some ZCML from a file. The default
+is ``ftesting.zcml``, but here we'll load a test ``testlayer.zcml``.
+
+ >>> from zope.component.testlayer import ZCMLFileLayer
+ >>> zcml_file_layer = ZCMLFileLayer(
+ ... zope.component.testfiles,
+ ... 'testlayer.zcml')
+
+ >>> class TestCase(unittest.TestCase):
+ ... layer = zcml_file_layer
+ ...
+ ... def testFoo(self):
+ ... # we should now have the adapter registered
+ ... from zope import component
+ ... from zope.component.testfiles import components
+ ... self.assert_(isinstance(
+ ... components.IApp2(components.content), components.Comp2))
+
+Since the ZCML sets up an adapter, we expect the tests to pass::
+
+ >>> suite = unittest.TestSuite()
+ >>> suite.addTest(unittest.makeSuite(TestCase))
+ >>> runner = Runner(found_suites=[suite])
+ >>> succeeded = runner.run()
+ Running zope.component.testfiles.ZCMLFileLayer tests:
+ Set up zope.component.testfiles.ZCMLFileLayer in ... seconds.
+ Ran 1 tests with 0 failures and 0 errors in ... seconds.
+ Tearing down left over layers:
+ Tear down zope.component.testfiles.ZCMLFileLayer in ... seconds.
+
Modified: zope.component/trunk/src/zope/component/tests.py
===================================================================
--- zope.component/trunk/src/zope/component/tests.py 2010-01-21 16:48:33 UTC (rev 108363)
+++ zope.component/trunk/src/zope/component/tests.py 2010-01-21 17:31:43 UTC (rev 108364)
@@ -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