[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