[Checkins] SVN: z3c.testsetup/branches/ulif-cleanup/src/z3c/testsetup/README_NEW.txt Add new central README which should only cover the core cases, but all

Uli Fouquet uli at gnufix.de
Sat Oct 24 08:44:50 EDT 2009


Log message for revision 105251:
  Add new central README which should only cover the core cases, but all
  of them.
  

Changed:
  A   z3c.testsetup/branches/ulif-cleanup/src/z3c/testsetup/README_NEW.txt

-=-
Added: z3c.testsetup/branches/ulif-cleanup/src/z3c/testsetup/README_NEW.txt
===================================================================
--- z3c.testsetup/branches/ulif-cleanup/src/z3c/testsetup/README_NEW.txt	                        (rev 0)
+++ z3c.testsetup/branches/ulif-cleanup/src/z3c/testsetup/README_NEW.txt	2009-10-24 12:44:49 UTC (rev 105251)
@@ -0,0 +1,943 @@
+z3c.testsetup
+*************
+
+Find and register your tests in a Zope environment.
+
+`z3c.testsetup` finds doctests and regular Python
+unittests and registers them.
+
+To accomplish this, you have to mark your testfiles with special
+restructured text-style markers explained below.
+
+
+Preliminaries
+=============
+
+We set up a sample package in which we can put our testfiles and their
+setups.
+
+We clear the commandline params, because all parameters passed to the
+commandline would otherwise be applied to the examples herein:
+
+    >>> import sys
+    >>> sys.argv = [sys.argv[0],]
+
+As `z3c.testsetup` searches packages, we create a package first:
+
+    >>> import os
+    >>> from os.path import join
+    >>> def create_sample_pkg():
+    ...   os.mkdir('sample')
+    ...   open(join('sample', '__init__.py'), 'wb').write("")
+    >>> create_sample_pkg()
+
+We make this new package findable:
+
+    >>> import sys
+    >>> sys.path.append(os.getcwd())
+
+Finding testfiles
+=================
+
+Testfiles are recognized by `z3c.testsetup` when they contain special
+markers in restructed-text-style. The most important ones are::
+
+  :doctest:
+
+if a testfile contains doctests and::
+
+  :unittest:
+
+if a testfile contains regular Python unittest (i.e. not doctests).
+
+.. note:: How to disable markers or make them invisible
+
+   All markers can be written as restructured text comments (two leading dots
+   followed by whitespace) like this::
+
+     .. :doctest:
+
+  and will still work. This way you can make the markers disappear
+  from autogenerated docs etc.
+
+Having marked your testfiles in a Python module, you have to write at
+least one setup module that finds the testfiles and turns them into a
+`unittest.TestSuite` instance.
+
+With `z3c.testsetup` the latter comes normally down to a simple call
+of the main test registration function::
+
+  z3c.testsetup.register_all_tests(<PKG_DOTTED_NAME>)
+
+where ``<PGK_DOTTED_NAME>`` is the dotted name of the package you want
+to search for testfiles or the package itself. The function returns a
+testsuite created of all testfiles found.
+
+
+Doctests
+========
+
+Doctests are recognized by `z3c.testsetup` when they contain a marker::
+
+  :doctest:
+
+We create such a doctest file in our sample package:
+
+    >>> open(join('sample', 'mytest.txt'), 'wb').write("""
+    ...
+    ... :doctest:
+    ...
+    ... A simple doctest.
+    ...
+    ...   >>> 1+1
+    ...   2
+    ...
+    ... """)
+
+And add a setup file where we tell that the `sample` package should be
+searched for test files. This can be accomplished by calling
+``z3c.testsetup.register_all_tests()``:
+
+    >>> open(join('sample', 'test_sample.py'), 'wb').write("""
+    ... import z3c.testsetup
+    ... test_suite = z3c.testsetup.register_all_tests('sample')
+    ... """)
+
+Now we run the doctest:
+
+    >>> defaults = [
+    ...   '--path', 'sample',
+    ...   '--tests-pattern', '^test_.*$',
+    ... ]
+    >>> from z3c.testsetup import testrunner
+    >>> testrunner.run(defaults)
+    Running zope.testing.testrunner.layer.UnitTests tests:
+      Set up zope.testing.testrunner.layer.UnitTests in N.NNN seconds.
+      Ran 1 tests with 0 failures and 0 errors in N.NNN seconds.
+    Tearing down left over layers:
+      Tear down zope.testing.testrunner.layer.UnitTests in N.NNN seconds.
+    False
+
+Also Python modules that contain doctests (and the required
+``:doctest:`` marker) are found:
+
+    >>> open(join('sample', 'mytest.py'), 'wb').write("""
+    ... '''
+    ... This Python module contains a doctest:
+    ...
+    ... :doctest:
+    ... 
+    ...   >>> 1+1
+    ...   2
+    ...
+    ... '''
+    ... def foo():
+    ...   return 'blah'
+    ...
+    ... """)
+    >>> testrunner.run(defaults)
+    Running zope.testing.testrunner.layer.UnitTests tests:
+      Set up zope.testing.testrunner.layer.UnitTests in N.NNN seconds.
+      Ran 2 tests with 0 failures and 0 errors in N.NNN seconds.
+    Tearing down left over layers:
+      Tear down zope.testing.testrunner.layer.UnitTests in N.NNN seconds.
+    False
+
+Beside this files with ``.rst`` filename extension are found by
+default.
+
+Regular unittests
+=================
+
+Regular Python unittests are recognized by `z3c.testsetup` when they
+contain a marker::
+
+  :unittest:
+
+We create such a module in our sample package:
+
+    >>> open(join('sample', 'mytest.py'), 'wb').write('''
+    ... """
+    ... Tests with real TestCase objects.
+    ...
+    ... :unittest:
+    ...
+    ... """
+    ... import unittest
+    ...
+    ... class TestTest(unittest.TestCase):
+    ...
+    ...   def setUp(self):
+    ...     pass
+    ...
+    ...   def testFoo(self):
+    ...     self.assertEqual(2, 1+1)
+    ...
+    ... ''')
+
+The testrunner will find this test:
+
+    >>> testrunner.run(defaults)
+    Running zope.testing.testrunner.layer.UnitTests tests:
+      Set up zope.testing.testrunner.layer.UnitTests in N.NNN seconds.
+      Ran 2 tests with 0 failures and 0 errors in N.NNN seconds.
+    Tearing down left over layers:
+      Tear down zope.testing.testrunner.layer.UnitTests in N.NNN seconds.
+    False
+
+
+Customzing registration
+=======================
+
+You can finetune some aspects of test registration, especially for
+doctests.
+
+Encoding
+--------
+
+When doctests are registered you can specify an encoding for
+these. The testrunner will then decode the testfile before processing
+it according to the given encoding. Tests results can be different when
+run with different encodings. By default the encoding is set to
+'utf-8'.
+
+You can set the used encoding (or ``None`` to avoid decoding of
+doctestfiles at all) by using the ``encoding`` parameter of
+``register_all_tests``:
+
+    >>> os.unlink(join('sample', 'test_sample.pyc'))
+    >>> open(join('sample', 'test_encodedsample.py'), 'wb').write("""
+    ... import z3c.testsetup
+    ... test_suite = z3c.testsetup.register_all_tests(
+    ...   'sample', encoding='utf-8')
+    ... """)
+
+This will handle utf-8 umlauts correctly:
+
+    >>> open(join('sample', 'mytest.txt'), 'wb').write(r"""
+    ...
+    ... A doctest with umlauts.
+    ...
+    ... :doctest:
+    ... 
+    ...   >>> myvar = u'ä'
+    ...   >>> myvar
+    ...   u'\xe4'
+    ...
+    ... """)
+
+    >>> defaults = [
+    ...   '--path', 'sample',
+    ...   '--tests-pattern', '^test_encodedsample.*$',
+    ... ]
+    >>> testrunner.run(defaults)
+    Running zope.testing.testrunner.layer.UnitTests tests:
+      Set up zope.testing.testrunner.layer.UnitTests in N.NNN seconds.
+      Ran 2 tests with 0 failures and 0 errors in N.NNN seconds.
+    Tearing down left over layers:
+      Tear down zope.testing.testrunner.layer.UnitTests in N.NNN seconds.
+    False
+
+If we run this test without encoding, we will get a different result:
+
+    >>> open(join('sample', 'test_unencodedsample.py'), 'wb').write("""
+    ... import z3c.testsetup
+    ... test_suite = z3c.testsetup.register_all_tests(
+    ...   'sample', encoding=None)
+    ... """)
+
+    >>> defaults = [
+    ...   '--path', 'sample',
+    ...   '--tests-pattern', '^test_unencoded.*$',
+    ... ]
+    >>> testrunner.run(defaults)
+    Running zope.testing.testrunner.layer.UnitTests tests:
+      Set up zope.testing.testrunner.layer.UnitTests in N.NNN seconds.
+    ...
+    Failed example:
+        myvar
+    Differences (ndiff with -expected +actual):
+        - u'\xe4'
+        + u'\xc3\xa4'
+    <BLANKLINE>
+      Ran 2 tests with 1 failures and 0 errors in N.NNN seconds.
+    Tearing down left over layers:
+      Tear down zope.testing.testrunner.layer.UnitTests in N.NNN seconds.
+    True
+
+If we set an encoding not capable of utf-8 umlauts, even the test
+registration will fail:
+
+    >>> open(join('sample', 'test_asciisample.py'), 'wb').write("""
+    ... import z3c.testsetup
+    ... test_suite = z3c.testsetup.register_all_tests(
+    ...   'sample', encoding='ascii')
+    ... """)
+
+    >>> defaults = [
+    ...   '--path', 'sample',
+    ...   '--tests-pattern', '^test_asciisample.*$',
+    ... ]
+    >>> testrunner.run(defaults)
+    Test-module import failures:
+    <BLANKLINE>
+    Module: test_asciisample
+    <BLANKLINE>
+    Traceback (most recent call last):
+    UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 ...
+    ...
+    Test-modules with import problems:
+      test_asciisample
+    Total: 0 tests, 0 failures, 0 errors in 0.000 seconds.
+    True
+
+In regular Python unittests you specify the encoding of the file by
+writing::
+
+ # -*- coding: <ENCODING> -*-
+
+
+Globals
+-------
+
+You can define a dictionary of names and things that should be
+available immediately (without imports) during tests. Default is an
+empty dict for normal doctests.
+
+If you apply a ZCML layer (see section 'layers') to your doctest you
+will automatically get some handy functions for handling ZODB stuff.
+
+To set a dict of globals for all tests, you can use the ``globs``
+option of `register_all_tests`:
+
+
+In our testsetup file we define a function ``somefunc`` and register
+it under the name ``mycustomfunc`` in ``globs``:
+
+    >>> open(join('sample', 'test_globssample.py'), 'wb').write("""
+    ... import z3c.testsetup
+    ...
+    ... def somefunc():
+    ...   return 'works'
+    ...
+    ... test_suite = z3c.testsetup.register_all_tests(
+    ...   'sample', globs=dict(mycustomfunc=somefunc))
+    ... """)
+
+This way the function will be available during doctests without
+import:
+
+    >>> open(join('sample', 'mytest.txt'), 'wb').write("""
+    ...
+    ... :doctest:
+    ...
+    ... A doctest that expects globs.
+    ...
+    ...   >>> mycustomfunc()
+    ...   'works'
+    ...
+    ... """)
+
+    >>> defaults = [
+    ...   '--path', 'sample',
+    ...   '--tests-pattern', '^test_globssample.*$',
+    ... ]
+    >>> testrunner.run(defaults)
+    Running zope.testing.testrunner.layer.UnitTests tests:
+      Set up zope.testing.testrunner.layer.UnitTests in N.NNN seconds.
+      Ran 2 tests with 0 failures and 0 errors in N.NNN seconds.
+    Tearing down left over layers:
+      Tear down zope.testing.testrunner.layer.UnitTests in N.NNN seconds.
+    False
+
+Another option to set test globals is to use the approriate setup and
+teardown functions for registration (see below, don't mix this setup
+functions up with layer setups;).
+
+The ``globs`` parameter applies only to doctests, not to plain python
+unittests.
+
+
+Checkers
+--------
+
+Checkers are output normalizers for doctests. ``None`` by default. A
+typical output checker can be created like this:
+
+    >>> open(join('sample', 'test_checkersample.py'), 'wb').write("""
+    ... import re
+    ... import z3c.testsetup
+    ... from zope.testing import renormalizing
+    ...
+    ... mychecker = renormalizing.RENormalizing([
+    ...    (re.compile('[0-9]*[.][0-9]* seconds'),
+    ...     '<SOME NUMBER OF> seconds'),
+    ...    (re.compile('at 0x[0-9a-f]+'), 'at <SOME ADDRESS>'),
+    ... ])
+    ...
+    ...
+    ... test_suite = z3c.testsetup.register_all_tests(
+    ...   'sample', checker=mychecker)
+    ... """)
+
+This would match for example output like ``0.123 seconds`` if you
+write in your doctest::
+
+      <SOME NUBMER OF> seconds
+
+The checker is registered with all tests by passing it as ``checker``
+option to the ``register_all_tests()`` call. Since version 0.5
+checkers are applied to both regular and functional doctests (pre-0.5:
+only functional ones).
+
+In our doctest we can now use ``<SOME NUMBER OF> seconds.``:
+
+    >>> open(join('sample', 'mytest.txt'), 'wb').write("""
+    ...
+    ... :doctest:
+    ...
+    ... A doctest that expects a special checker.
+    ...
+    ...   >>> print '2.123 seconds elapsed'
+    ...   <SOME NUMBER OF> seconds elapsed
+    ...
+    ...   >>> print '0.123 seconds elapsed'
+    ...   <SOME NUMBER OF> hours elapsed
+    ...
+    ... """)
+
+    >>> defaults = [
+    ...   '--path', 'sample',
+    ...   '--tests-pattern', '^test_checkersample.*$',
+    ... ]
+    >>> testrunner.run(defaults)
+    Running zope.testing.testrunner.layer.UnitTests tests:
+    ...
+    File "/sample/mytest.txt", line 10, in mytest.txt
+    Failed example:
+        print 'N.NNN seconds elapsed'
+    Differences (ndiff with -expected +actual):
+        - <SOME NUMBER OF> hours elapsed
+        ?                  ^ ^^
+        + <SOME NUMBER OF> seconds elapsed
+        ?                  ^^^ ^^
+      Ran 2 tests with 1 failures and 0 errors in N.NNN seconds.
+    Tearing down left over layers:
+      Tear down zope.testing.testrunner.layer.UnitTests in N.NNN seconds.
+    True
+
+The second example in doctest apparently failed because we expected
+the wrong string.
+
+
+Optionflags
+-----------
+
+Optionflags influence the behaviour of the testrunner. They are
+logically or'd so that you can add them arithmetically. See
+
+  http://svn.zope.org/zope.testing/trunk/src/zope/testing/doctest.py
+
+for details. The default is::
+
+    optionflags = (zope.testing.doctest.ELLIPSIS+
+                   zope.testing.doctest.NORMALIZE_WHITESPACE+
+                   zope.testing.doctest.REPORT_NDIFF)
+
+You can set optionflags for tests by passing the ``optionflags``
+parameter to ``register_all_tests()``. For example we could require a
+different output format:
+
+    >>> open(join('sample', 'test_udiffsample.py'), 'wb').write("""
+    ... import z3c.testsetup
+    ... from zope.testing import doctest
+    ... 
+    ... myflags = (doctest.ELLIPSIS+
+    ...            doctest.NORMALIZE_WHITESPACE+
+    ...            doctest.REPORT_UDIFF)
+    ...
+    ... test_suite = z3c.testsetup.register_all_tests(
+    ...   'sample', optionflags=myflags)
+    ... """)
+
+If we run the following (erraneous) doctest:
+
+    >>> open(join('sample', 'mytest.txt'), 'wb').write("""
+    ...
+    ... :doctest:
+    ...
+    ...   >>> 1+1
+    ...   3
+    ...
+    ... """)
+
+we get the following error message:
+
+    >>> defaults = [
+    ...   '--path', 'sample',
+    ...   '--tests-pattern', '^test_udiffsample.*$',
+    ... ]
+    >>> testrunner.run(defaults)
+    Running zope.testing.testrunner.layer.UnitTests tests:
+    ...
+    Failed example:
+        1+1
+    Expected:
+        3
+    Got:
+        2
+    ...
+
+while with optionflag `doctest.REPORT_NDIFF`:
+
+    >>> open(join('sample', 'test_ndiffsample.py'), 'wb').write("""
+    ... import z3c.testsetup
+    ... from zope.testing import doctest
+    ... 
+    ... myflags = (doctest.ELLIPSIS+
+    ...            doctest.NORMALIZE_WHITESPACE+
+    ...            doctest.REPORT_NDIFF)
+    ...
+    ... test_suite = z3c.testsetup.register_all_tests(
+    ...   'sample', optionflags=myflags)
+    ... """)
+
+we get ndiffed output:
+
+    >>> defaults = [
+    ...   '--path', 'sample',
+    ...   '--tests-pattern', '^test_ndiffsample.*$',
+    ... ]
+    >>> testrunner.run(defaults)
+    Running zope.testing.testrunner.layer.UnitTests tests:
+    ...
+    Failed example:
+        1+1
+    Differences (ndiff with -expected +actual):
+        - 3
+        + 2
+    ...
+
+The ``optionflags`` parameter applies only to doctests, not to plain
+python unittests.
+
+
+Setup and teardown functions
+----------------------------
+
+You can specify setup and teardown functions to be executed before and
+after a single test respictevely. Please do not mix up this
+*registration* functions with the setUp and tearDown methods of layers.
+
+This functions, if given, must accept a single parameter, the test to
+be registered. Using this functions you can for instance modify the
+set of globals for this very test or similar things.
+
+    >>> open(join('sample', 'test_setupsample.py'), 'wb').write("""
+    ... import z3c.testsetup
+    ...
+    ... def mysetup(test):
+    ...   print "SETUP ", test
+    ...
+    ... def myteardown(test):
+    ...   print "TEARDOWN ", test
+    ...
+    ... def myspecialsetup(test):
+    ...   print "SPECIAL SETUP ", test
+    ... 
+    ... def myspecialteardown(test):
+    ...   print "SPECIAL TEARDOWN ", test
+    ... 
+    ... test_suite = z3c.testsetup.register_all_tests(
+    ...   'sample', setup=mysetup, teardown=myteardown)
+    ... """)
+
+    >>> open(join('sample', 'mytest.txt'), 'wb').write("""
+    ...
+    ... :doctest:
+    ...
+    ...   >>> 1+1
+    ...   2
+    ...
+    ... """)
+
+    >>> defaults = [
+    ...   '--path', 'sample',
+    ...   '--tests-pattern', '^test_setupsample.*$',
+    ... ]
+    >>> testrunner.run(defaults)
+    Running zope.testing.testrunner.layer.UnitTests tests:
+      Set up zope.testing.testrunner.layer.UnitTests in N.NNN seconds.
+    SETUP  <DocTest mytest.txt from /sample/mytest.txt:0 (1 example)>
+    TEARDOWN  <DocTest mytest.txt from /sample/mytest.txt:0 (1 example)>
+      Ran 2 tests with 0 failures and 0 errors in N.NNN seconds.
+    Tearing down left over layers:
+      Tear down zope.testing.testrunner.layer.UnitTests in N.NNN seconds.
+    False
+
+There is no special setup nor teardown function registered by default.
+
+The functions passed to ``register_all_tests()`` will be applied to
+every single doctest file registered. If you want a special
+setup/teardown function for a special doctest file only, you can
+override this by specifying a::
+
+  :setup: <DOTTED_PATH_TO_FUNCDEF>
+
+or::
+
+  :teardown: <DOTTED_PATH_TO_FUNCDEF>
+
+marker in your doctest file. We defined ``myspecialsetup(test)`` in
+the setup above which we can now reference in an additional doctest
+file:
+
+    >>> open(join('sample', 'mytest2.txt'), 'wb').write("""
+    ...
+    ... :doctest:
+    ... :setup: sample.test_setupsample.myspecialsetup
+    ... :teardown: sample.test_setupsample.myspecialteardown
+    ...
+    ...   >>> 1+1
+    ...   2
+    ...
+    ... """)
+
+    >>> defaults = [
+    ...   '--path', 'sample',
+    ...   '--tests-pattern', '^test_setupsample.*$',
+    ... ]
+    >>> testrunner.run(defaults)
+    Running zope.testing.testrunner.layer.UnitTests tests:
+      Set up zope.testing.testrunner.layer.UnitTests in N.NNN seconds.
+    SETUP  <DocTest mytest.txt from /sample/mytest.txt:0 (1 example)>
+    TEARDOWN  <DocTest mytest.txt from /sample/mytest.txt:0 (1 example)>
+    SPECIAL SETUP  <DocTest mytest2.txt from ... (1 example)>
+    SPECIAL TEARDOWN  <DocTest mytest2.txt from ... (1 example)>
+      Ran 3 tests with 0 failures and 0 errors in N.NNN seconds.
+    Tearing down left over layers:
+      Tear down zope.testing.testrunner.layer.UnitTests in N.NNN seconds.
+    False
+
+Here we can see, that 'mytest.txt' was setup using the parameter
+options passed to ``register_all_tests()`` while 'mytest2.txt' used
+special setup and teardown functions.
+
+Again, this options (``setup`` and ``teardown``) apply to doctests
+only. Regular Python unittests can define their own setup and teardown
+functions in test cases.
+
+Clean up:
+
+    >>> os.unlink(join('sample', 'mytest2.txt'))
+
+
+Tearing down layers
+-------------------
+
+If you use ZCML layers (see below) then you can specify whether the
+layers are allowed to be torn down after test runs by the testrunner.
+
+The default is ``None`` which means: use the default of
+`zope.app.testing` (currently: ``False``).
+
+We create a minimal ftesting.zcml:
+
+    >>> open(join('sample', 'ftesting.zcml'), 'wb').write("""
+    ... <configure
+    ...   xmlns="http://namespaces.zope.org/zope"
+    ...   i18n_domain="zope"
+    ... />
+    ... """)
+    
+A doctest that makes use of this ZCML file:
+
+    >>> open(join('sample', 'mytest.txt'), 'wb').write("""
+    ...
+    ... :doctest:
+    ... :zcml-file: ftesting.zcml
+    ... 
+    ...   >>> 1+1
+    ...   2
+    ...
+    ... """)
+
+A setup that uses the default teardown (no ``allow_teardown`` option used):
+
+    >>> open(join('sample', 'test_defaultteardownsample.py'), 'wb').write("""
+    ... import z3c.testsetup
+    ...
+    ... test_suite = z3c.testsetup.register_all_tests(
+    ...   'sample')
+    ... """)
+
+When we run this doctest:
+
+    >>> defaults = [
+    ...   '--path', 'sample',
+    ...   '--tests-pattern', '^test_defaultteardownsample.*$',
+    ... ]
+    >>> testrunner.run(defaults)
+    Running z3c...DefaultZCMLLayer [/sample/ftesting.zcml] tests:
+    ...
+      Tear down z3c...DefaultZCMLLayer [/sample/ftesting.zcml] ... not supported
+    ...
+
+we get a ``not supported`` message.
+
+If we setup tests to allow teardown:
+
+    >>> open(join('sample', 'test_allowteardownsample.py'), 'wb').write("""
+    ... import z3c.testsetup
+    ...
+    ... test_suite = z3c.testsetup.register_all_tests(
+    ...   'sample', allow_teardown=True)
+    ... """)
+
+    >>> defaults = [
+    ...   '--path', 'sample',
+    ...   '--tests-pattern', '^test_allowteardownsample.*$',
+    ... ]
+    >>> testrunner.run(defaults)
+    Running z3c...DefaultZCMLLayer [/sample/ftesting.zcml] tests:
+    ...
+      Tear down z3c...DefaultZCMLLayer [/sample/ftesting.zcml] in N.NNN seconds.
+    ...
+
+ZCML backed tests are torn down.
+
+
+Layers
+======
+
+The `zope.testing` machinery provides the concept of layers to group
+tests.
+
+
+Simple doctest layers
+---------------------
+
+We create a simple doctest layer:
+
+    >>> open(join('sample', 'layers.py'), 'wb').write("""
+    ... class MyLayer(object):
+    ...   '''A simple layer.
+    ...   '''
+    ...   @classmethod
+    ...   def setUp(self):
+    ...     print "SET UP CUSTOM LAYER"
+    ...
+    ...   @classmethod
+    ...   def tearDown(self):
+    ...     print "TEAR DOWN CUSTOM LAYER"
+    ...
+    ...   @classmethod
+    ...   def testSetUp(self):
+    ...     print "CUSTOM TEST SETUP"
+    ... 
+    ...   @classmethod
+    ...   def testTearDown(self):
+    ...     print "CUSTOM  TEST TEARDOWN"
+    ... 
+    ... """)
+
+To let this layer take action, we use the::
+
+  :layer: <DOTTED_NAME_OF_LAYERDEF>
+
+marker in our doctest:
+
+    >>> open(join('sample', 'mytest.txt'), 'wb').write("""
+    ...
+    ... :doctest:
+    ... :layer: sample.layers.MyLayer
+    ... 
+    ...   >>> 1+1
+    ...   2
+    ...
+    ... """)
+
+When we run the test, the classmethods of the layer will be executed
+before and after the tests respectively.
+
+    >>> defaults = [
+    ...   '--path', 'sample',
+    ...   '--tests-pattern', '^test_sample.*$',
+    ... ]
+    >>> testrunner.run(defaults)
+    Running sample.layers.MyLayer tests:
+      Set up sample.layers.MyLayer SET UP CUSTOM LAYER
+    in N.NNN seconds.
+    CUSTOM TEST SETUP
+    CUSTOM  TEST TEARDOWN
+      Ran 1 tests with 0 failures and 0 errors in N.NNN seconds.
+    Running zope.testing.testrunner.layer.UnitTests tests:
+      Tear down sample.layers.MyLayer TEAR DOWN CUSTOM LAYER
+    in N.NNN seconds.
+      Set up zope.testing.testrunner.layer.UnitTests in N.NNN seconds.
+      Ran 1 tests with 0 failures and 0 errors in N.NNN seconds.
+    Tearing down left over layers:
+      Tear down zope.testing.testrunner.layer.UnitTests in N.NNN seconds.
+    Total: 2 tests, 0 failures, 0 errors in N.NNN seconds.
+    False
+
+
+ZCML layers
+-----------
+
+ZCML layers are a special kind of layer widely used within Zope
+testing. If you define a ZCML layer, a complete ZODB test instance
+will be setup for you in background so that so-called ``functional
+tests`` can be performed. ZCML layers are called so as they require a
+ZCML file to define the setup.
+
+.. note:: ZCML layers require `zope.app.testing`
+
+  To make use of ZCML layers `zope.app.testing` must be available
+  during test runs.
+
+There are at least two ways to define a ZCML layer for doctests.
+
+
+1) Using ``:zcml-file:`` marker
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You can set a ``:zcml-file:`` marker in your doctest to request
+creation of ZCML layers during test runs.
+
+The marker requires the filename of a ZCML file to parse::
+
+  :zcml-file: <ZCML_FILENAME>
+
+We create a very plain ZCML file:
+
+    >>> open(join('sample', 'ftesting.zcml'), 'wb').write("""
+    ... <configure
+    ...   xmlns="http://namespaces.zope.org/zope"
+    ...   i18n_domain="zope"
+    ... />
+    ... """)
+
+Note that this simple setup will not give much results, as Zope needs
+more information to setup fully-fledged environments.
+
+Now we create a doctest that makes use of this ZCML layer:
+
+    >>> open(join('sample', 'mytest.txt'), 'wb').write("""
+    ...
+    ... :doctest:
+    ... :zcml-file: ftesting.zcml
+    ... 
+    ...   >>> getRootFolder
+    ...   <function getRootFolder at 0x...>
+    ...
+    ... """)
+
+In this doctest a function `getRootFolder()` will be available in
+namespace. Other functions automatically included in namespace are
+``sync()`` and ``http()``.
+
+When we run the tests, functional layers will be created:
+
+    >>> defaults = [
+    ...   '--path', 'sample',
+    ...   '--tests-pattern', '^test_sample.*$',
+    ... ]
+    >>> testrunner.run(defaults)
+    Running z3c...DefaultZCMLLayer [/sample/ftesting.zcml] tests:
+      Set up z3c...DefaultZCMLLayer [/sample/ftesting.zcml] in N.NNN seconds.
+      Ran 1 tests with 0 failures and 0 errors in N.NNN seconds.
+    Running zope.testing.testrunner.layer.UnitTests tests:
+      Tear down z3c...DefaultZCMLLayer [/sample/ftesting.zcml] ... not supported
+    Total: 1 tests, 0 failures, 0 errors in N.NNN seconds.
+    False
+
+2) Manually setting up ZCML layers
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Using the ``:layer:`` marker you can also setup your own ZCML
+layer for a given doctest:
+
+    >>> open(join('sample', 'zcmllayers.py'), 'wb').write("""
+    ... import os
+    ... from zope.app.testing.functional import ZCMLLayer
+    ... 
+    ... class MyFunctionalLayer(ZCMLLayer):
+    ... 
+    ...   def setUp(self):
+    ...     '''Set up '''
+    ...     # ZCMLLayer is an old-style class. super() therefore won't work.
+    ...     ZCMLLayer.setUp(self)
+    ...     # and now my stuff
+    ... 
+    ...   def tearDown(self):
+    ...     '''Tear down'''
+    ...     # first my stuff
+    ...     ZCMLLayer.tearDown(self)
+    ... 
+    ... ftesting_zcml = os.path.join(os.path.dirname(__file__), 
+    ...                              'ftesting.zcml')
+    ... FunctionalLayer = MyFunctionalLayer(
+    ...   ftesting_zcml, __name__, 'MyFunctionalLayer', allow_teardown=True)
+    ...
+    ... """)
+
+Note that here we also create a layer *instance* and not only define a
+class (as with plain unittest layers).
+
+Of course you can also leave out the custom layer definition and define
+a bare ZCMLLayer from `zope.app.testing.functional`.
+
+In our doctest we will use the layer defined and instantiated above:
+
+    >>> open(join('sample', 'mytest.txt'), 'wb').write("""
+    ...
+    ... :doctest:
+    ... :layer: sample.zcmllayers.FunctionalLayer
+    ... 
+    ...   >>> getRootFolder
+    ...   <function getRootFolder at 0x...>
+    ...
+    ... """)
+
+    >>> open(join('sample', 'test_customzcmlsample.py'), 'wb').write("""
+    ... import z3c.testsetup
+    ...
+    ... test_suite = z3c.testsetup.register_all_tests(
+    ...   'sample', allow_teardown=True)
+    ... """)
+
+
+    >>> defaults = [
+    ...   '--path', 'sample',
+    ...   '--tests-pattern', '^test_customzcmlsample.*$',
+    ... ]
+    >>> testrunner.run(defaults)
+    Running sample.zcmllayers.MyFunctionalLayer tests:
+      Set up sample.zcmllayers.MyFunctionalLayer in N.NNN seconds.
+      Ran 1 tests with 0 failures and 0 errors in N.NNN seconds.
+    Running zope.testing.testrunner.layer.UnitTests tests:
+      Tear down sample.zcmllayers.MyFunctionalLayer in N.NNN seconds.
+      Set up zope.testing.testrunner.layer.UnitTests in N.NNN seconds.
+      Ran 1 tests with 0 failures and 0 errors in N.NNN seconds.
+    Tearing down left over layers:
+      Tear down zope.testing.testrunner.layer.UnitTests in N.NNN seconds.
+    Total: 2 tests, 0 failures, 0 errors in N.NNN seconds.
+    False
+
+
+Layers in regular Python unittests
+----------------------------------
+
+`zope.testing` supports layers also for regular Python unittests. To
+enable this feature, your testcases have to provide a ``layer``
+attribute wich should contain the required layer.
+
+As this is not within the scope of `z3c.testsetup` we skip examples
+here.
+
+
+Clean up:
+
+    >>> import shutil
+    >>> shutil.rmtree('sample')



More information about the checkins mailing list