[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