[Checkins] SVN: z3c.testsetup/trunk/ Merge changes from new_markers into trunk.
Uli Fouquet
uli at gnufix.de
Wed Jan 7 11:08:24 EST 2009
Log message for revision 94595:
Merge changes from new_markers into trunk.
Changed:
U z3c.testsetup/trunk/CHANGES.txt
U z3c.testsetup/trunk/README.txt
U z3c.testsetup/trunk/setup.py
A z3c.testsetup/trunk/src/z3c/testsetup/HOWTO_UPGRADE.txt
D z3c.testsetup/trunk/src/z3c/testsetup/README.txt
A z3c.testsetup/trunk/src/z3c/testsetup/README.txt
U z3c.testsetup/trunk/src/z3c/testsetup/doctesting.py
A z3c.testsetup/trunk/src/z3c/testsetup/functional/layer.py
U z3c.testsetup/trunk/src/z3c/testsetup/functional/testgetter.py
U z3c.testsetup/trunk/src/z3c/testsetup/nozopeapptesting.txt
U z3c.testsetup/trunk/src/z3c/testsetup/pythontestsetup.txt
U z3c.testsetup/trunk/src/z3c/testsetup/testgetter.py
U z3c.testsetup/trunk/src/z3c/testsetup/testgetter.txt
U z3c.testsetup/trunk/src/z3c/testsetup/testing.py
A z3c.testsetup/trunk/src/z3c/testsetup/tests/README_OLD.txt
A z3c.testsetup/trunk/src/z3c/testsetup/tests/othercave/
U z3c.testsetup/trunk/src/z3c/testsetup/tests/test_testsetup.py
A z3c.testsetup/trunk/src/z3c/testsetup/tests/util.txt
U z3c.testsetup/trunk/src/z3c/testsetup/unittestsetup.txt
U z3c.testsetup/trunk/src/z3c/testsetup/util.py
-=-
Modified: z3c.testsetup/trunk/CHANGES.txt
===================================================================
--- z3c.testsetup/trunk/CHANGES.txt 2009-01-07 16:03:12 UTC (rev 94594)
+++ z3c.testsetup/trunk/CHANGES.txt 2009-01-07 16:08:23 UTC (rev 94595)
@@ -23,7 +23,53 @@
by using ``module_info_from_dotted_name`` and
``module_info_from_package`` from the ``martian.scan`` package.
+Feature Changes
+---------------
+* New set of testfile markers:
+
+ - `:doctest:`
+
+ marks a testfile as a doctest.
+
+ - `:unittest:`
+
+ marks a testfile as a regular unittest.
+
+ - `:layer: dotted.name.to.layer.def`
+
+ applies the given layer definition to the tests in the doctest
+ file.
+
+ - `:zcml-layer: filename.zcml`
+
+ sets up a ZCML layer with the given filename and applies this
+ layer to the doctests in the doctest file.
+
+ - `:functional-zcml-layer: filename.zcml`
+
+ sets up a ZCML layer with the given filename and applies this
+ layer to the doctests in the doctest file. Furthermore the tests
+ are set up as functional doc tests.
+
+ - `:setup: dotted.name.to.setup.function`
+
+ applies the setUp function denoted by the dotted name to the tests
+ in the doctest file.
+
+ - `:teardown: dotted.name.to.teardown.function`
+
+ applies the tearDown function denoted by the dotted name to the
+ tests in the doctests file.
+
+ See the examples in `tests/othercave` and README.txt to learn more
+ about using these new directives.
+
+ The old `:test-layer:` marker is still supported but it is
+ deprecated now and will vanish at least with the 0.5 version of
+ `z3c.testsetup`.
+
+
0.2.2 (2008-02-29)
==================
Modified: z3c.testsetup/trunk/README.txt
===================================================================
--- z3c.testsetup/trunk/README.txt 2009-01-07 16:03:12 UTC (rev 94594)
+++ z3c.testsetup/trunk/README.txt 2009-01-07 16:08:23 UTC (rev 94595)
@@ -29,6 +29,14 @@
Note, that this is alphaware! Do not use it in productive
environments!
+**Important Note:**
+
+ This version of ``z3c.testsetup`` uses a new set of testfile markers
+ than previous releases did. If you are still using `Test-Layer:
+ unit` or similar, please read the README.txt in the source directory
+ carefully to learn how to switch to the new names.
+
+
Prerequisites
=============
Modified: z3c.testsetup/trunk/setup.py
===================================================================
--- z3c.testsetup/trunk/setup.py 2009-01-07 16:03:12 UTC (rev 94594)
+++ z3c.testsetup/trunk/setup.py 2009-01-07 16:08:23 UTC (rev 94595)
@@ -17,6 +17,8 @@
+ '\n'
+ read('src', 'z3c', 'testsetup', 'README.txt')
+ '\n\n'
+ + read('src', 'z3c', 'testsetup', 'HOWTO_UPGRADE.txt')
+ + '\n\n'
+ read('CHANGES.txt')
+ '\n\n'
+ 'Download\n'
Copied: z3c.testsetup/trunk/src/z3c/testsetup/HOWTO_UPGRADE.txt (from rev 94594, z3c.testsetup/branches/new_markers/src/z3c/testsetup/HOWTO_UPGRADE.txt)
===================================================================
--- z3c.testsetup/trunk/src/z3c/testsetup/HOWTO_UPGRADE.txt (rev 0)
+++ z3c.testsetup/trunk/src/z3c/testsetup/HOWTO_UPGRADE.txt 2009-01-07 16:08:23 UTC (rev 94595)
@@ -0,0 +1,34 @@
+How to upgrade from `z3c.testsetup` < 0.3
+=========================================
+
+With the 0.3 release of `z3c.testsetup` the set of valid marker
+strings changed, introducing support for file-dependent setups,
+layers, etc.
+
+If you still mark your testfiles with the ``:Test-Layer:`` marker,
+update your testfiles as follows:
+
+- ``:Test-Layer: unit``
+
+ Change to: ``:doctest:``
+
+- ``:Test-Layer: python``
+
+ Change to: ``:unittest:``
+
+- ``:Test-Layer: functional``
+
+ Change to: ``:functional-zcml-layer: <ZCML-FILE>``
+
+ The ZCML file must explicitly be given.
+
+If you used custom setups passed to ``register_all_tests``, consider
+declaring those setup/teardown functions in the appropriate doctest
+files using ``:setup:`` and ``:teardown:``.
+
+You might also get better structured test suites when using the new
+layer markers ``:layer:``, ``:zcml-layer:`` and
+``functional-zcml-layer:``.
+
+Try to get rid of all parameters passed to ``register_all_tests``
+except those, mentioned in ``README.txt``.
Deleted: z3c.testsetup/trunk/src/z3c/testsetup/README.txt
===================================================================
--- z3c.testsetup/trunk/src/z3c/testsetup/README.txt 2009-01-07 16:03:12 UTC (rev 94594)
+++ z3c.testsetup/trunk/src/z3c/testsetup/README.txt 2009-01-07 16:08:23 UTC (rev 94595)
@@ -1,525 +0,0 @@
-z3c.testsetup
-*************
-
-Easy testsetups for Zope 3 and Python projects.
-
-Setting up tests for Zope 3 projects sometimes tends to be
-cumbersome. ``z3c.testsetup`` jumps in here, to support much flatter
-test setups. The package supports three kinds of tests:
-
-- normal python tests: i.e. tests, that consist of python modules
- which in turn contain ``unittest.TestCase`` classes.
-
-- unit doctests: i.e. tests, that are written as doctests, but require
- no complicated layer setup etc.
-
-- functional doctests: i.e. tests, that are written as doctests, but
- also require a more or less complex framework to test for example
- browser requests.
-
-``z3c.testsetup`` is package-oriented. That means, it registers more or
-less automatically all the three kinds of tests mentioned above
-insofar they are part of a certain package.
-
-This is a general introduction to ``z3c.testsetup``. For setup
-examples you might see the ``cave`` package contained in the `tests/`
-directory. More details on special topics can be found in the
-appropriate .txt files in this directory.
-
-
-Basic Example
-=============
-
-The shortest test setup possible with ``z3c.testsetup`` looks like
-this::
-
- >>> import z3c.testsetup
- >>> test_suite = z3c.testsetup.register_all_tests(
- ... 'z3c.testsetup.tests.cave')
-
-It is sufficient to put this lines into a python module which is found
-by your testrunner (see `samplesetup_short` examples in the ``cave``
-package and ``testrunner.txt``).
-
-To sum it up, testsetup with ``z3c.testsetup`` is done in two steps:
-
-1) Make sure your testfiles are named properly (.txt/.rst for
- doctests, valid python modules for usual unit tests) and provide a
- suitable marker string as explained below (`How to mark
- testfiles/modules`_).
-
-2) Write a test setup module which is named so that your testrunner
- finds it and in this module call::
-
- test_suite = z3c.testsetup.register_all_tests(<package>)
-
- where ``<package>`` must be a package object. Instead of a package
- object you can also pass the package's dotted name as string like
- `'z3c.testsetup.tests.cave'`.
-
-Given that, this setup should find all doctests (unit and functional)
-as well as python tests in the package and register them.
-
-
-Customized Setups
-=================
-
-The `register_all_tests` function mentioned above accepts a bunch of
-keyword parameters::
-
- register_all_tests(pkg_or_dotted_name, filter_func, extensions,
- encoding, checker,
- globs, setup, teardown, optionflags
- zcml_config, layer_name, layer)
-
-where all but the first parameter are keyword paramters and all but
-the package parameter are optional.
-
-While `filter_func` and `extensions` determine the set of testfiles to
-be found, the other paramters tell how to setup single tests.
-
-
-- **filter_func** (**ufilter_func**, **ffilter_func**)
-
- a function that takes an absolute filepath and returns `True` or
- `False`, depending on whether the file should be included in the
- test suite as doctest or not. `filter_func` applies only to
- doctests.
-
- We setup a few things to check that::
-
- >>> import os
- >>> import unittest
- >>> suite = test_suite()
- >>> suite.countTestCases()
- 4
-
- Okay, the callable in `test_suite` we created above with
- `register_all_tests` apparently delivered four testcases. This is
- normally also the number of files involved, but let's check that
- correctly.
-
- We did setup a function `get_basenames_from_suite` in this testing
- environment (as a `globs` entry) which determines the basenames of
- the paths of all testcases contained in a `TestSuite`::
-
- >>> get_basenames_from_suite(suite)
- ['file1.py', 'file1.rst', 'file1.txt', 'subdirfile.txt']
-
- Ah, okay. There are in fact four files, in which testcases were
- found. Now, we define a plain filter function::
-
- >>> def custom_file_filter(path):
- ... """Accept all txt files."""
- ... return path.endswith('.txt')
-
- This one accepts all '.txt' files. We run `register_all_tests`
- again, but this time with a `filter_func` parameter::
-
- >>> test_suite = z3c.testsetup.register_all_tests(
- ... 'z3c.testsetup.tests.cave',
- ... filter_func=custom_file_filter)
-
- To get the resulting test suite, we again call the returned
- callable::
-
- >>> suite = test_suite()
- >>> get_basenames_from_suite(suite)
- ['file1.py', 'file1.txt', 'file1.txt', 'subdirfile.txt',
- 'subdirfile.txt']
-
- Compared with the first call to `register_all_tests` we got some
- strange results here: there is a '.py' file, which should have been
- refused by our filter function and the other two files appear
- twice. What happened?
-
- The python module is included, because python tests are not
- filtered by `filter_func`. Instead this value applies only to
- doctests.
-
- The second strange result, that every .txt file appears twice in
- the list, comes from the fact, that the filter is valid for unit
- and functional doctests at the same time. In other words: the tests
- in those .txt files are registered twice, as unittests and a second
- time as functional tests as well.
-
- If you want a filter function for functional doctests or unit
- doctests only, then you can use `ffilter_func` and `ufilter_func`
- respectively::
-
- >>> test_suite = z3c.testsetup.register_all_tests(
- ... 'z3c.testsetup.tests.cave',
- ... ffilter_func=custom_file_filter,
- ... ufilter_func=lambda x: False)
-
- >>> suite = test_suite()
- >>> get_basenames_from_suite(suite)
- ['file1.py', 'file1.txt', 'subdirfile.txt']
-
- As expected, every .txt file was only registered once. The same
- happens, when we switch and accept only unit doctests::
-
- >>> test_suite = z3c.testsetup.register_all_tests(
- ... 'z3c.testsetup.tests.cave',
- ... ffilter_func=lambda x: False,
- ... ufilter_func=custom_file_filter)
-
- >>> suite = test_suite()
- >>> get_basenames_from_suite(suite)
- ['file1.py', 'file1.txt', 'subdirfile.txt']
-
- If you specify both, a `filter_func` and a more specialized
- `ufilter_func` or `ffilter_func`, then this has the same effect as
- passing both, `ufilter_func` and `ffilter_func`::
-
- >>> test_suite = z3c.testsetup.register_all_tests(
- ... 'z3c.testsetup.tests.cave',
- ... ffilter_func=lambda x: False,
- ... filter_func=custom_file_filter)
-
- >>> suite = test_suite()
- >>> get_basenames_from_suite(suite)
- ['file1.py', 'file1.txt', 'subdirfile.txt']
-
-
-- **pfilter_func**:
-
- Does basically the same as the ``filter_funcs`` above, but handles
- Python modules instead of file paths. It therefore determines the
- set of 'normal' Python tests accepted and does not touch the set
- of doctests accepted.
-
- We define a simple custom filter::
-
- >>> def custom_module_filter(module_info):
- ... return 'Tests with real' in open(module_info.path, 'r').read()
-
- that checks for a certain string in modules' doc strings.
-
- Now we start again with `pfilter_func` set::
-
- >>> test_suite = z3c.testsetup.register_all_tests(
- ... 'z3c.testsetup.tests.cave',
- ... pfilter_func=custom_module_filter)
- >>> suite = test_suite()
- >>> get_basenames_from_suite(suite)
- ['file1.py', 'file1.rst', 'file1.txt', 'notatest2.py', 'subdirfile.txt']
-
- Because file1.py and notatest2.py in the cave package contain the
- required string, this is correct. Because the default function
- checks for the string `:Test-Layer: python`, the second module was
- omitted by default.
-
- Now let's use a filter, that refuses all modules::
-
- >>> test_suite = z3c.testsetup.register_all_tests(
- ... 'z3c.testsetup.tests.cave',
- ... pfilter_func=lambda x: False)
- >>> suite = test_suite()
- >>> get_basenames_from_suite(suite)
- ['file1.rst', 'file1.txt', 'subdirfile.txt']
-
- All Python modules vanished from the list.
-
- In case you wonder, why not all the other Python files of the
- `cave` package (`__init__.py`, for example) appear in one of the
- lists: we get only the result list, which contains only such
- modules, which provide `unittest.TestCase` definitions. Because
- most modules of the `cave` package don't define test cases, they
- do not appear in the list. This automatism is driven by a
- `unittest.TestLoader`. See
- http://docs.python.org/lib/testloader-objects.html to learn more
- about test loaders.
-
-
-- **extensions** (**uextensions**, **fextensions**):
-
- a list of filename extensions to be considered during test
- search. Default value is `['.txt', '.rst']`. Python tests are not
- touched by this (they have to be regular Python modules with '.py'
- extension).
-
- Note, that the `extensions` attribute is used by the default
- filter function. If you pass your own filter function using
- `[u|f]filter_func`, then the extensions filtering won't work any
- more.
-
- If we want to register .foo files, we can do so::
-
- >>> test_suite = z3c.testsetup.register_all_tests(
- ... 'z3c.testsetup.tests.cave',
- ... extensions=['.foo'])
- >>> suite = test_suite()
- >>> get_basenames_from_suite(suite)
- ['file1.py', 'notatest1.foo', 'notatest1.foo']
-
- Note, that only files that contain an appropriate marker are
- found, regardless of the filename extension. The new .foo file
- contains a marker for unit doctests and functional doctests, such
- it is included twice in the list.
-
- As we can see, the new file appears twice. This is, because it is
- registered as functional doctest and unitdoctest as well.
-
- To collect only functional doctests with a certain set of filename
- extensions you can use: `fextensions`::
-
- >>> test_suite = z3c.testsetup.register_all_tests(
- ... 'z3c.testsetup.tests.cave',
- ... fextensions=['.foo'])
- >>> suite = test_suite()
- >>> get_basenames_from_suite(suite)
- ['file1.py', 'file1.rst', 'notatest1.foo']
-
- Here the .rst file were registered as unit doctest, while the .foo
- file was registered as functional doctest.
-
- To collect only unit doctests with a different set of filename
- extensions you can use `uextensions`::
-
- >>> test_suite = z3c.testsetup.register_all_tests(
- ... 'z3c.testsetup.tests.cave',
- ... uextensions=['.foo'])
- >>> suite = test_suite()
- >>> get_basenames_from_suite(suite)
- ['file1.py', 'file1.txt', 'notatest1.foo', 'subdirfile.txt']
-
- Here the .foo file was registered as unit doctest and the .txt
- files as functional ones.
-
-
-- **encoding**:
-
- the encoding of testfiles. 'utf-8' by default. Setting this to `None`
- means using the default value. We've hidden one doctest file, that
- contains umlauts. If we set the encoding to `ascii`, we get an
- error::
-
- >>> test_suite = z3c.testsetup.register_all_tests(
- ... 'z3c.testsetup.tests.cave',
- ... encoding='ascii')
- >>> suite = test_suite()
- Traceback (most recent call last):
- ...
- UnicodeDecodeError: 'ascii' codec can't decode ...: ordinal
- not in range(128)
-
- While using 'latin-1' will work::
-
- >>> test_suite = z3c.testsetup.register_all_tests(
- ... 'z3c.testsetup.tests.cave',
- ... encoding='latin-1')
- >>> suite = test_suite()
-
- No traceback here.
-
- You can always overwrite an encoding setting for a certain file by
- following PEP 0263 ( http://www.python.org/dev/peps/pep-0263/ ).
-
-
-- **checker**:
-
- An output checker for functional doctests. `None` by default. A
- typical output checker can be created like this::
-
- >>> import re
- >>> 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>'),
- ... ])
-
- This would match for example output like `0.123 seconds` if you
- write in your doctest::
-
- <SOME NUBMER OF> seconds
-
- Please see ``testrunner.txt`` for examples of usage.
-
- Checkers are applied to functional doctests only!
-
-- **globs**:
-
- A dictionary of things that should be available immediately
- (without imports) during tests. Defaults are::
-
- dict(http=HTTPCaller(),
- getRootFolder=getRootFolder,
- sync=sync)
-
- for functional doctests and an empty dict for unit
- doctests. Python test globals can't be set this way.
-
- If you want to register special globals for functional doctest or
- unit doctests only, then you can use the `fglobs` and/or `uglobs`
- keyword respectively. These keywords replace any `globs` value for
- the respective kind of tests.
-
- For more extensive examples see ``testrunner.txt``.
-
-- **setup**:
-
- A function that takes a `test` argument and is executed before
- every single doctest. By default it runs::
-
- zope.app.testing.functional.FunctionalTestSetup().setUp()
-
- for functional doctests and an empty function for unit
- doctests. Python tests provide their own setups.
-
- If you want to register special setup-functions for either
- functional or unit doctests, then you can pass keyword parameters
- `fsetup` or `usetup` respectively.
-
-- **teardown**:
-
- The equivalent to `setup`. Runs by default::
-
- FunctionalTestSetup().tearDown()
-
- for functional doctests and::
-
- zope.testing.cleanup.cleanUp()
-
- for unit doctests. Python tests have to provide their own teardown
- functions in TestCases.
-
-- **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.
-
-- **zcml_config**:
-
- A filepath of a ZCML file which is registered with functional
- doctests. In the ZCML file you can for example register principals
- (users) usable by functional doctests.
-
- By default any `ftesting.zcml` file from the root of the given
- package is taken. If this does not exist, an empty ZCML file of
- the z3c.testsetup package is used (``ftesting.zcml``).
-
- This parameter has no effect, if also a ``layer`` parameter is
- given.
-
-- **layer_name**:
-
- You can name your layer, to distinguish different setups of
- functional doctests. The layer name can be an arbitrary string.
-
- This parameter has no effect, if also a ``layer`` parameter is
- given.
-
-- **layer**:
-
- You can register a ZCML layer yourself and pass it as the
- ``layer`` parameter. If you only have a filepath to the according
- ZCML file, use the ``zcml_config`` paramter instead.
-
- This parameter overrides any ``zcml_config`` and ``layer_name``
- parameter.
-
-
-How to mark testfiles/modules
-=============================
-
-To avoid non-wanted files and modules to be registered, you have to
-mark your wanted test files/modules with a special string explicitly:
-
-- python modules you want to register must provide a module docstring
- that contains a line::
-
- :Test-Layer: python
-
- A module doctring is written at the top of file like this:
-
- **Python Unit Test Example:**::
-
- """
- A module that tests things.
-
- :Test-Layer: python
-
- """
- import unittest
- class MyTest(unittest.TestCase):
- def testFoo(self):
- pass
-
-
-- doctest files that contain unit tests must provide a string::
-
- :Test-Layer: unit
-
- to be registered. Futhermore, their filename extension must be by
- default '.txt' or '.rst'. A file `sampletest.txt` with a unit
- doctest therefore might look like this:
-
- **Unit Doctest Example 1:**::
-
- ==========
- My package
- ==========
-
- :Test-Layer: unit
-
- This is documentation for the MyPackage package.
-
- >>> 1+1
- 2
-
- Also python modules which contain tests in doctests notation are
- doctests. As rule of thumb you can say: if a module contains tests
- that are written preceeded by '>>>', then this is a doctest. If
- ``unittest.TestCase`` classes are defined, then it is a 'normal'
- python testfile. Another valid unit doctest module therefore can
- look like this:
-
- **Unit Doctest Example 2:**::
-
- """
- ==========
- My package
- ==========
-
- A package for doing things.
-
- :Test-Layer: unit
-
- We check for basic things::
-
- >>> 1+1
- 2
-
- """
- class MyClass:
- pass
-
-
-- files that contain functional doctests must provide a string::
-
- :Test-Layer: functional
-
- to be registered. Furthermore they must by default have a filename
- extension `.txt` or `.rst`. A file `sampletest.txt` with functional
- tests might look like this:
-
- **Functional Doctest Example:**::
-
- ==========
- My package
- ==========
-
- :Test-Layer: functional
-
- This is documentation for the MyPackage package.
-
- >>> 1+1
- 2
-
-
Copied: z3c.testsetup/trunk/src/z3c/testsetup/README.txt (from rev 94594, z3c.testsetup/branches/new_markers/src/z3c/testsetup/README.txt)
===================================================================
--- z3c.testsetup/trunk/src/z3c/testsetup/README.txt (rev 0)
+++ z3c.testsetup/trunk/src/z3c/testsetup/README.txt 2009-01-07 16:08:23 UTC (rev 94595)
@@ -0,0 +1,749 @@
+z3c.testsetup
+*************
+
+Easy testsetups for Zope 3 and Python projects.
+
+Setting up tests for Zope 3 projects sometimes tends to be
+cumbersome. ``z3c.testsetup`` jumps in here, to support much flatter
+test setups. The package supports normal Python `unit tests
+<http://docs.python.org/library/unittest.html>`_ and
+`doctests <http://docs.python.org/library/doctest.html>`_.
+
+Note, that if you want integration or functional tests, that you have
+to make sure, that the ``zope.app.testing`` package is available
+during test runs. ``z3c.testsetup`` does **not** depend on it.
+
+The package works in two steps:
+
+1) It looks for testfiles in a given package.
+
+2) It registers the tests according to your specifications.
+
+.. note: Important note for users of ':Test-Layer:':
+
+ The marker strings of `z3c.testsetup` changed!
+
+ Please switch to the new syntax described below, if you are still
+ using the old ':Test-Layer:' marker. It is more powerful and less
+ magic.
+
+This is a general introduction to ``z3c.testsetup``. For setup
+examples you might see the ``othercave`` package contained in the
+`tests/` directory. More details on special topics can be found in the
+appropriate .txt files in this directory.
+
+
+Basic Example
+=============
+
+Before we can find, register and execute tests, we first have to write
+them down. We already have some ready to use tests available, which
+can be found in a subpackage::
+
+ >>> import os
+ >>> cavepath = os.path.dirname(__file__)
+ >>> cavepath = os.path.join(cavepath, 'tests', 'othercave')
+
+In this subpackage there is a simple doctest `doctest01.txt` (please
+ignore the pipes on the left)::
+
+ >>> print_file(os.path.join(cavepath, 'doctest01.txt'))
+ | A doctest
+ | =========
+ |
+ | :doctest:
+ |
+ | This is a simple doctest.
+ |
+ | >>> 1+1
+ | 2
+ |
+
+
+As we can see, the doctest is marked by a special marker
+
+ `:doctest:`.
+
+This marker tells the testsetup machinery, that this file contains
+doctest examples that should be registered during test runs. Without
+this marker, a testfile won't be registered during tests!
+
+This is the only difference to 'normal' doctests here.
+
+Other markers detected by ``z3c.testsetup`` are:
+
+ - ``:unittest:``
+
+ A replacement for ``:doctest:``, marking a Python module as
+ containing unittests to run. Replaces old ``Test-Layer: python``
+ marker.
+
+ - ``:setup: <dotted.name.of.function>``
+
+ Execute the given setup function before running doctests in this
+ file.
+
+ - ``:teardown: <dotted.name.of.function>``
+
+ Execute the given teardown function after running doctests in this
+ file.
+
+ - ``:layer: <dotted.name.of.layer.def>``
+
+ Use the given layer definition for tests in this file.
+
+ - ``:zcml-layer: <ZCML_filename>``
+
+ Use the given ZCML file and run tests in this file on a ZCML
+ layer. Tests are registered using
+ `zope.testing.doctest.DocFileSuite`.
+
+ - ``:functional-zcml-layer: <ZCML_filename>``
+
+ Use the given ZCML file and run tests in this file registered with
+ `zope.app.testing.functional.DocFileSuite`.
+
+See below for explanations of the respective markers.
+
+.. note:: How to disable markers or make them invisible
+
+ All markers can be written as restructured text comment (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. Markers are case-insensitive. If you
+ want to disable a test, just turn ``:doctest:`` into ``:nodoctest:``
+ and the file will be ignored.
+
+Now, that we have a doctest available, we can write a testsetup
+routine, that collects all tests, registers them and passes them to
+the testrunner.
+
+We have such a simple testsetup already available::
+
+ >>> print open(os.path.join(cavepath, 'simplesetup01.py')).read()
+ import z3c.testsetup
+ test_suite = z3c.testsetup.register_all_tests(
+ 'z3c.testsetup.tests.othercave')
+
+This is all we need in simple cases. We use
+
+ `register_all_tests(<dotted_pkg_name>)`
+
+to tell the setup machinery, where to look for test files. Note, that
+also files in subpackages will be found, registered and executed, when
+they are marked approriately.
+
+Let's start the testrunner and see what it gives::
+
+ >>> import sys
+ >>> sys.argv = [sys.argv[0],]
+ >>> defaults = [
+ ... '--path', cavepath,
+ ... '--tests-pattern', '^simplesetup01$',
+ ... ]
+ >>> from zope.testing import testrunner
+ >>> testrunner.run(defaults)
+ Running z3c...functional.layer.DefaultZCMLLayer [ftesting.zcml] tests:
+ Set up z3c....layer.DefaultZCMLLayer [ftesting.zcml] in N.NNN seconds.
+ Ran 3 tests with 0 failures and 0 errors in N.NNN seconds.
+ Running z3c...functional.layer.DefaultZCMLLayer [ftesting2.zcml] tests:
+ Tear down z3c...layer.DefaultZCMLLayer [ftesting.zcml] ... not supported
+ Running in a subprocess.
+ Set up z3c...layer.DefaultZCMLLayer [ftesting2.zcml] in N.NNN seconds.
+ Ran 1 tests with 0 failures and 0 errors in N.NNN seconds.
+ Tear down z3c...layer.DefaultZCMLLayer [ftesting2.zcml] ... not supported
+ Running z3c.testsetup.tests.othercave.testing.UnitLayer2 tests:
+ Running in a subprocess.
+ Set up z3c.testsetup.tests.othercave.testing.UnitLayer1 in N.NNN seconds.
+ Set up z3c.testsetup.tests.othercave.testing.UnitLayer2 in N.NNN seconds.
+ Running testSetUp of UnitLayer1
+ Running testSetUp of UnitLayer2
+ Running testTearDown of UnitLayer2
+ Running testTearDown of UnitLayer1
+ Ran 1 tests with 0 failures and 0 errors in N.NNN seconds.
+ Tear down z3c...tests.othercave.testing.UnitLayer2 in N.NNN seconds.
+ Tear down z3c...tests.othercave.testing.UnitLayer1 in N.NNN seconds.
+ Running zope.testing.testrunner.layer.UnitTests tests:
+ Running in a subprocess.
+ Set up zope.testing.testrunner.layer.UnitTests in N.NNN seconds.
+ Custom setUp for <DocTest doctest05.txt from ... (2 examples)>
+ Custom tearDown for <DocTest doctest05.txt from ... (2 examples)>
+ Ran 7 tests with 0 failures and 0 errors in N.NNN seconds.
+ Tear down zope.testing.testrunner.layer.UnitTests in N.NNN seconds.
+ Total: 12 tests, 0 failures, 0 errors in N.NNN seconds.
+ False
+
+As we can see, there were regular unittests as well as functional
+tests run. Some of the unittests used their own layer (``UnitLayer1``)
+whose location were printed and the functional tests used different
+ZCML-files for configuration.
+
+Of course, there were more tests than only the ones defined in
+``doctest01.txt``. Let's have a look at the other stuff.
+
+
+Defining doctests in Python modules
+-----------------------------------
+
+The doctest file described above was a pure .txt file. By default
+``z3c.testsetup`` looks for doctests in files with filename extension
+``.txt``, ``.rst`` and ``.py``. This means, that also doctests in
+Python modules are found by default as in the following example::
+
+ >>> print_file(os.path.join(cavepath, 'doctest08.py'))
+ | """
+ | Doctests in a Python module
+ | ===========================
+ |
+ | We can place doctests also in Python modules.
+ |
+ | :doctest:
+ |
+ | Here the Cave class is defined::
+ |
+ | >>> from z3c.testsetup.tests.othercave.doctest08 import Cave
+ | >>> Cave
+ | <class 'z3c.testsetup...doctest08.Cave'>
+ |
+ | """
+ | class Cave(object):
+ | """A Cave.
+ |
+ | A cave has a number::
+ |
+ | >>> hasattr(Cave, 'number')
+ | True
+ |
+ | """
+ | number = None
+ |
+ | def __init__(self, number):
+ | """Create a Cave.
+ |
+ | We have to give a number if we create a cave::
+ |
+ | >>> c = Cave(12)
+ | >>> c.number
+ | 12
+ |
+ | """
+ | self.number = number
+ |
+
+Here we placed the marker string ``:doctest:`` into the docstring of
+the module. Without it, the module would not have been considered a
+testfile.
+
+Note that you have to import the entities (classes, functions, etc.)
+from the very same file if you want to use them.
+
+
+Registering regular unittests from Python modules
+-------------------------------------------------
+
+``z3c.testsetup`` provides also (limited) support for regular
+`unittest` deployments as usually written in Python. An example file
+could look like this::
+
+ >>> print_file(os.path.join(cavepath, 'pythontest1.py'))
+ | """
+ | 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 module contains a marker ``:unittest:`` in its module docstring
+instead of the ``:doctest:`` marker used in the other examples
+above. It is also the replacement for the formely used ``:Test-Layer:
+python`` marker.
+
+This means, that this file is registered as a regular unittest.
+
+If you use unittests instead of doctests, then you are mainly on your
+own with setting up and tearing down tests. All this should be done by
+the test cases themselves.
+
+The only advantage of using ``z3c.testsetup`` here is, that those
+tests are found and run automatically when they provide the marker.
+
+
+``register_all_tests()``
+========================
+
+The `register_all_tests` function mentioned above accepts a bunch of
+keyword parameters::
+
+ register_all_tests(pkg_or_dotted_name [, extensions] [, encoding]
+ [, checker] [, globs] [, optionflags]
+ [, setup] [, teardown]
+ [, zcml_config] [, layer_name] [, layer])
+
+where all but the first parameter are keyword paramters and all but
+the package parameter are optional.
+
+While the `extensions` parameter determines the set of testfiles to be
+found, the other paramters tell how to setup single tests.
+
+The last five parameters are only fallbacks, that should better be
+configured in doctest files themselves via marker strings.
+
+- **extensions**:
+
+ a list of filename extensions to be considered during doctest
+ search. Default value for doctests is `['.txt', '.rst',
+ '.py']`. Python tests are not touched by this (they have to be
+ regular Python modules with '.py' extension).
+
+ If we want to register .foo files, we can do so::
+
+ >>> import z3c.testsetup
+ >>> test_suite = z3c.testsetup.register_all_tests(
+ ... 'z3c.testsetup.tests.cave',
+ ... extensions=['.foo'])
+ >>> suite = test_suite()
+ >>> get_basenames_from_suite(suite)
+ ['file1.py', 'notatest1.foo', 'notatest1.foo']
+
+ Note, that only files that contain an appropriate marker are
+ found, regardless of the filename extension.
+
+
+- **encoding**:
+
+ the encoding of testfiles. 'utf-8' by default. Setting this to `None`
+ means using the default value. We've hidden one doctest file, that
+ contains umlauts. If we set the encoding to `ascii`, we get an
+ error::
+
+ >>> test_suite = z3c.testsetup.register_all_tests(
+ ... 'z3c.testsetup.tests.cave',
+ ... encoding='ascii')
+ >>> suite = test_suite()
+ Traceback (most recent call last):
+ ...
+ UnicodeDecodeError: 'ascii' codec can't decode ...: ordinal
+ not in range(128)
+
+ While using 'latin-1' will work::
+
+ >>> test_suite = z3c.testsetup.register_all_tests(
+ ... 'z3c.testsetup.tests.cave',
+ ... encoding='latin-1')
+ >>> suite = test_suite()
+
+ No traceback here.
+
+ You can always overwrite an encoding setting for a certain file by
+ following PEP 0263 ( http://www.python.org/dev/peps/pep-0263/ ).
+
+
+- **checker**:
+
+ An output checker for doctests. `None` by default. A typical
+ output checker can be created like this::
+
+ >>> import re
+ >>> 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>'),
+ ... ])
+
+ This would match for example output like `0.123 seconds` if you
+ write in your doctest::
+
+ <SOME NUBMER OF> seconds
+
+ Please see ``testrunner.txt`` for examples of usage.
+
+ Checkers are applied to functional doctests only!
+
+
+- **globs**:
+
+ A dictionary of things that should be available immediately
+ (without imports) during tests. Default is an empty dict, which
+ might be populated by appropriate layers (see below). ZCML layers
+ for example get you the ``getRootFolder`` method automatically.
+
+ This parameter is a fallback which can be overriden by testfile
+ markers specifying a certain layer (see below).
+
+ The `globs` parameter applies only to doctests.
+
+
+- **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.
+
+
+- **setup**:
+
+ A callable that takes a `test` argument and is executed before
+ every single doctest.
+
+ The default function does nothing.
+
+ This parameter is a fallback which can be overriden by testfile
+ markers specifying a certain layer (see below).
+
+ Specifying setup functions in a layer is also the recommended way.
+
+
+- **teardown**:
+
+ The equivalent to `setup`.
+
+ The default function runs
+
+ zope.testing.cleanup.cleanUp()
+
+ unless overriden by a layer.
+
+ Specifying teardown functions in a layer is also the recommended
+ way.
+
+
+- **zcml_config**:
+
+ A filepath of a ZCML file which is registered with functional
+ doctests. In the ZCML file you can for example register principals
+ (users) usable by functional doctests.
+
+ By default any `ftesting.zcml` file from the root of the given
+ package is taken. If this does not exist, an empty ZCML file of
+ the z3c.testsetup package is used (``ftesting.zcml``).
+
+ This parameter has no effect, if also a ``layer`` parameter is
+ given or a docfile specifies its own layer/ZCML config (see below).
+
+ This is a fallback parameter. Use of docfile specific layer markers
+ is recommended.
+
+
+- **layer_name**:
+
+ You can name your layer, to distinguish different setups of
+ functional doctests. The layer name can be an arbitrary string.
+
+ This parameter has no effect, if also a ``layer`` parameter is
+ given or a docfile specifies its own layer/ZCML config (see
+ below).
+
+ This is a fallback parameter. Use of docfile specific layer
+ markers is recommended.
+
+- **layer**:
+
+ You can register a ZCML layer yourself and pass it as the
+ ``layer`` parameter. If you only have a filepath to the according
+ ZCML file, use the ``zcml_config`` paramter instead.
+
+ This parameter overrides any ``zcml_config`` and ``layer_name``
+ parameter.
+
+ This is a fallback parameter and has no effect for docfiles
+ specifying their own layer or ZCML config.
+
+
+Deprectated/unsupported parameters
+----------------------------------
+
+The following ``register_all_tests``-parameters are deprecated,
+starting with ``z3c.testsetup`` 0.3:
+
+- **filter_func**
+
+ and related (``ufilter_func``, ``pfilter_func``, etc.)
+
+- All testtype specific parameters
+
+ Support for testfile specific parameters (``uextensions``,
+ ``fextensions``, etc.) is running out and its use deprecated.
+
+
+Layers and setup/teardown functions
+===================================
+
+Starting with ``z3c.testsetup`` 0.3 there is first reasonable support
+for setting up layers per testfile. This way you can easily create
+setup-functions that are only run before/after certain tests.
+
+Overall, use of layers is the recommended way from now on.
+
+
+Setting up a unittest layer
+---------------------------
+
+We can tell ``z3c.testsetup`` to use a certain unittest layer using
+the ``:layer:`` marker as in the following example (see
+``tests/othercave/doctest02.txt``)::
+
+ A doctests with layer
+ =====================
+ <BLANKLINE>
+ :doctest:
+ :layer: z3c.testsetup.tests.othercave.testing.UnitLayer2
+ <BLANKLINE>
+ >>> 1+1
+ 2
+
+
+The ``:doctest:`` marker was used here as well, because without it the
+file would not have been detected as a registerable doctest file (we
+want developers to be explicit about that).
+
+The
+
+ `:layer: <DOTTED_NAME_OF_LAYER_DEF>`
+
+marker then tells, where the testsetup machinery can
+find the layer definition. It is given in dotted name notation.
+
+How does the layer definition look like? It is defined as regualr
+Python code::
+
+ >>> print open(os.path.join(cavepath, 'testing.py')).read()
+ import os
+ ...
+ class UnitLayer1(object):
+ """This represents a layer.
+ A layer is a way to have common setup and teardown that happens
+ once for a whole group of tests.
+ <BLANKLINE>
+ It must be an object with a `setUp` and a `tearDown` method, which
+ are run once before or after all the tests applied to a layer
+ respectively.
+ <BLANKLINE>
+ Optionally you can additionally define `testSetUp` and
+ `testTearDown` methods, which are run before and after each single
+ test.
+ <BLANKLINE>
+ This class is not instantiated. Therefore we use classmethods.
+ """
+ <BLANKLINE>
+ @classmethod
+ def setUp(self):
+ """This gets run once for the whole test run, or at most once per
+ TestSuite that depends on the layer.
+ (The latter can happen if multiple suites depend on the layer
+ and the testrunner decides to tear down the layer after first
+ suite finishes.)
+ """
+ <BLANKLINE>
+ @classmethod
+ def tearDown(self):
+ """This gets run once for the whole test run, or at most
+ once per TestSuite that depends on the layer,
+ after all tests in the suite have finished.
+ """
+ <BLANKLINE>
+ @classmethod
+ def testSetUp(self):
+ """This method is run before each single test in the current
+ layer. It is optional.
+ """
+ print " Running testSetUp of UnitLayer1"
+ <BLANKLINE>
+ @classmethod
+ def testTearDown(self):
+ """This method is run before each single test in the current
+ layer. It is optional.
+ """
+ print " Running testTearDown of UnitLayer1"
+ <BLANKLINE>
+ class UnitLayer2(UnitLayer1):
+ """This Layer inherits ``UnitLayer1``.
+ <BLANKLINE>
+ This way we define nested setups. During test runs the testrunner
+ will first call the setup methods of ``UnitTest1`` and then those
+ of this class. Handling of teardown-methods will happen the other
+ way round.
+ """
+ <BLANKLINE>
+ @classmethod
+ def setUp(self):
+ pass
+ <BLANKLINE>
+ @classmethod
+ def testSetUp(self):
+ print " Running testSetUp of UnitLayer2"
+ <BLANKLINE>
+ @classmethod
+ def testTearDown(self):
+ print " Running testTearDown of UnitLayer2"
+
+In a layer you can do all the special stuff that is needed to run a
+certain group of tests properly. Our setup here is special in that we
+defined a nested one: ``UnitLayer2`` inherits ``UnitLayer1`` so that
+during test runs the appropriate setup and teardown methods are called
+(see testrunner output above).
+
+More about test layers can be found at the documentation of
+`testrunner layers API
+<http://apidoc.zope.org/++apidoc++/Code/zope/testing/testrunner-layers-api.txt/index.html>`_.
+
+Specifying a ZCML file
+----------------------
+
+When it comes to integration or functional tests, we need to specify a
+ZCML file to which configures the test environment for us. We can do
+that using the
+
+ `:zcml-layer: <ZCML-file-name>`
+
+marker. It expects a ZCML filename as argument and sets up a
+ZCML-layered testsuite for us. An example setup might look like so (see
+``tests/othercave/doctest03.txt``)::
+
+ A doctest with a ZCML-layer
+ ===========================
+
+ :doctest:
+ :zcml-layer: ftesting.zcml
+
+ >>> 1+1
+ 2
+
+.. note:: Requires ``zope.app.testing``
+
+ If you use ``:zcml-layer``, the ``zope.app.testing`` package must
+ be available when running the tests and during test setup. This
+ package is not fetched by default by ``z3c.testsetup``.
+
+Here we say, that the the local file ``ftesting.zcml`` should be used
+as ZCML configuration. As we can see in the above output of testruner,
+this file is indeed read during test runs and used by a ZCML layer
+called ``DefaultZCMLLayer``. This layer is in fact only a
+``zope.app.testing.functional.ZCMLLayer``.
+
+The ZCML file is looked up in the same directory as the doctest file.
+
+When using the ``:zcml-layer:`` marker, the concerned tests are set up
+via special methods and functions from `zope.app.testing`. This way
+you get 'functional' or 'integration' tests out of the box: in the
+beginning an empty ZODB db is setup, ``getRootFolder``, ``sync`` and
+other functions are pulled into the test namespace and several things
+more.
+
+If you want a plain setup instead then use your own layer definition
+using ``:layer:`` and remove the ``:zcml-layer:`` marker.
+
+
+Setting up a functional ZCML layer
+----------------------------------
+
+Sometimes we want tests to be registered using the
+``FunctionalDocFileSuite`` function from
+``zope.app.testing.functional`` (other tests are set up using
+``zope.testing.doctest.DocFileSuite``). This function pulls in even
+more functions into ``globs``, like ``http`` (a ``HTTPCaller``
+instance), wraps your ``setUp`` and ``tearDown`` methods into
+ZODB-setups and several things more. See the definition in
+http://svn.zope.org/zope.app.testing/trunk/src/zope/app/testing/functional.py?view=auto.
+
+This setup needs also a ZCML configuration file, which can be
+specified via::
+
+ :functional-zcml-layer: <ZCML-file-name>
+
+If a functional ZCML layer is specified in a testfile this way, it
+will override any simple ``:zcml-layer:`` or ``:layer:`` definition.
+
+An example setup might look like this (see
+``tests/othercave/doctest04.txt``)::
+
+ >>> print_file(os.path.join(cavepath, 'doctest04.txt'))
+ | A functional doctest with ZCML-layer
+ | ====================================
+ |
+ | :doctest:
+ | :functional-zcml-layer: ftesting.zcml
+ |
+ | We didn't define a real environment in ftesting.zcml, but in
+ | functional tests certain often needed functions should be available
+ | automatically::
+ |
+ | >>> getRootFolder()
+ | <zope.app.folder.folder.Folder object at 0x...>
+ |
+
+.. note:: Requires ``zope.app.testing``
+
+ If you use ``:zcml-layer``, the ``zope.app.testing`` package must
+ be available when running the tests and during test setup. This
+ package is not fetched by default by ``z3c.testsetup``.
+
+Specifying ``setUp`` and ``tearDown`` methods
+---------------------------------------------
+
+We can specify a ``setUp(test)`` and ``tearDown(test)`` method for the
+examples in a doctest file, which will be executed once for the whole
+doctest file. This can be done using::
+
+ :setup: <dotted.name.of.callable>
+ :teardown: <dotted.name.of.callable>
+
+The callables denoted by the dotted names must accept a ``test``
+parameter which will be the whole test suite of examples in the
+current doctest file.
+
+An example can be found in ``doctest05.txt``::
+
+ >>> print_file(os.path.join(cavepath, 'doctest05.txt'))
+ | A doctest with custom setup/teardown functions
+ | ==============================================
+ |
+ | :doctest:
+ | :setup: z3c.testsetup.tests.othercave.testing.setUp
+ | :teardown: z3c.testsetup.tests.othercave.testing.tearDown
+ |
+ | >>> 1+1
+ | 2
+ |
+ | We make use of a function registered during custom setup::
+ |
+ | >>> myfunc(2)
+ | 4
+ |
+
+The setup/teardown functions denoted in the example look like this::
+
+ >>> print open(os.path.join(cavepath, 'testing.py'), 'rb').read()
+ import os
+ ...
+ def setUp(test):
+ print " Custom setUp for ", test
+ # We register a function that will be available during tests.
+ test.globs['myfunc'] = lambda x: 2*x
+ <BLANKLINE>
+ def tearDown(test):
+ print " Custom tearDown for ", test
+ del test.globs['myfunc'] # unregister function
+ ...
+
+As we can see, there is a function ``myfunc`` pulled into the
+namespace of the doctest. We could, however, do arbitrary other things
+here, set up a relational test database or whatever.
Modified: z3c.testsetup/trunk/src/z3c/testsetup/doctesting.py
===================================================================
--- z3c.testsetup/trunk/src/z3c/testsetup/doctesting.py 2009-01-07 16:03:12 UTC (rev 94594)
+++ z3c.testsetup/trunk/src/z3c/testsetup/doctesting.py 2009-01-07 16:08:23 UTC (rev 94595)
@@ -15,9 +15,11 @@
"""
import unittest
import os.path
+from os import listdir
from zope.testing import doctest, cleanup
from z3c.testsetup.base import BasicTestSetup
-from z3c.testsetup.util import get_package, get_marker_from_file
+from z3c.testsetup.util import (get_package, get_marker_from_file, warn,
+ get_attribute)
class DocTestSetup(BasicTestSetup):
"""A test setup for doctests."""
@@ -40,8 +42,123 @@
self.globs = globs
if optionflags is not None:
self.optionflags = optionflags
-
+
+class SimpleDocTestSetup(DocTestSetup):
+ """A unified doctest setup for packages.
+ """
+
+ extensions = ['.rst', '.txt', '.py']
+
+ def getTestSuite(self):
+ docfiles = self.getDocTestFiles(package=self.package)
+ suite = unittest.TestSuite()
+ for name in docfiles:
+ layerdef = get_marker_from_file('layer', name)
+
+ zcml_layer = self.getZCMLLayer(name, 'zcml-layer')
+ if zcml_layer is not None:
+ layerdef = zcml_layer
+
+ functional_zcml_layer = self.getZCMLLayer(
+ name, 'functional-zcml-layer')
+ if functional_zcml_layer is not None:
+ layerdef = functional_zcml_layer
+
+ setup = get_marker_from_file('setup', name) or self.setUp
+ if setup is not None and isinstance(setup, basestring):
+ setup = get_attribute(setup)
+
+ teardown = get_marker_from_file('teardown', name) or self.tearDown
+ if teardown is not None and isinstance(teardown, basestring):
+ teardown = get_attribute(teardown)
+
+ if os.path.isabs(name):
+ # We get absolute pathnames, but we need relative ones...
+ common_prefix = os.path.commonprefix([self.package.__file__,
+ name])
+ name = name[len(common_prefix):]
+
+ suite_creator = doctest.DocFileSuite
+ if functional_zcml_layer is not None:
+ try:
+ from zope.app.testing.functional import (
+ FunctionalDocFileSuite)
+ except ImportError:
+ warn("""You specified `:functional-zcml-layer:` in
+ %s
+but there seems to be no `zope.app.testing` package available.
+Please include `zope.app.testing` in your project setup to run this testfile.
+""" % (os.path.join(common_prefix, name),))
+ continue
+ suite_creator = FunctionalDocFileSuite
+
+ test = suite_creator(
+ name,
+ package=self.package,
+ setUp=setup,
+ tearDown=teardown,
+ globs=self.globs,
+ optionflags=self.optionflags,
+ **self.additional_options
+ )
+ if layerdef is not None:
+ test.layer = layerdef
+ suite.addTest(test)
+ return suite
+
+ def getZCMLLayer(self, filepath, marker):
+ """Create a ZCML layer out of a test marker.
+ """
+ zcml_file = get_marker_from_file(marker, filepath)
+ if zcml_file is None:
+ return
+ try:
+ # Late import. Some environments don't have
+ # ``zope.app.testing`` available.
+ from z3c.testsetup.functional.layer import DefaultZCMLLayer
+ except ImportError:
+ warn("""You specified `%s` in
+ %s
+but there seems to be no `zope.app.testing` package available.
+Please include `zope.app.testing` in your project setup to run this testfile.
+""" % (marker, name))
+ layer = DefaultZCMLLayer(
+ os.path.join(os.path.dirname(filepath), zcml_file),
+ DefaultZCMLLayer.__module__,
+ '%s [%s]' % (DefaultZCMLLayer.__name__, zcml_file))
+ return layer
+
+ def isTestFile(self, filepath):
+ """Return ``True`` if a file matches our expectations for a
+ doctest file.
+ """
+ if os.path.splitext(filepath)[1].lower() not in self.extensions:
+ return False
+ if get_marker_from_file('doctest', filepath) is None:
+ return False
+ return True
+
+ def getDocTestFiles(self, dirpath=None, **kw):
+ """Find all doctest files filtered by filter_func.
+ """
+ if dirpath is None:
+ dirpath = os.path.dirname(self.package.__file__)
+ dirlist = []
+ for filename in listdir(dirpath):
+ abs_path = os.path.join(dirpath, filename)
+ if not os.path.isdir(abs_path):
+ if self.filter_func(abs_path):
+ dirlist.append(abs_path)
+ continue
+ # Search subdirectories...
+ if not self.isTestDirectory(abs_path):
+ continue
+ subdir_files = self.getDocTestFiles(dirpath=abs_path, **kw)
+ dirlist.extend(subdir_files)
+ return dirlist
+
+
class UnitDocTestSetup(DocTestSetup):
"""A unit test setup for packages.
Copied: z3c.testsetup/trunk/src/z3c/testsetup/functional/layer.py (from rev 94594, z3c.testsetup/branches/new_markers/src/z3c/testsetup/functional/layer.py)
===================================================================
--- z3c.testsetup/trunk/src/z3c/testsetup/functional/layer.py (rev 0)
+++ z3c.testsetup/trunk/src/z3c/testsetup/functional/layer.py 2009-01-07 16:08:23 UTC (rev 94595)
@@ -0,0 +1,22 @@
+##############################################################################
+#
+# Copyright (c) 2008 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.
+#
+##############################################################################
+"""Default layers.
+"""
+import os
+from zope.app.testing.functional import ZCMLLayer
+
+class DefaultZCMLLayer(ZCMLLayer, object):
+ def __init__(self, filepath, modname, layername, **kw):
+ super(DefaultZCMLLayer, self).__init__(
+ filepath, modname, layername, **kw)
Modified: z3c.testsetup/trunk/src/z3c/testsetup/functional/testgetter.py
===================================================================
--- z3c.testsetup/trunk/src/z3c/testsetup/functional/testgetter.py 2009-01-07 16:03:12 UTC (rev 94594)
+++ z3c.testsetup/trunk/src/z3c/testsetup/functional/testgetter.py 2009-01-07 16:08:23 UTC (rev 94595)
@@ -23,7 +23,8 @@
from z3c.testsetup.doctesting import UnitDocTestSetup
from z3c.testsetup.functional.doctesting import FunctionalDocTestSetup
from z3c.testsetup.testgetter import (BasicTestGetter, UnitDocTestGetter,
- PythonTestGetter, BasicTestCollector)
+ PythonTestGetter, BasicTestCollector,
+ SimpleDocTestGetter)
from z3c.testsetup.testing import UnitTestSetup
from z3c.testsetup.util import get_package, get_keyword_params
@@ -36,11 +37,12 @@
class DocTestCollector(BasicTestCollector):
"""A TestCollector that wraps functional doctests and unit doctests.
"""
- handled_getters = [FunctionalDocTestGetter, UnitDocTestGetter]
+ handled_getters = [FunctionalDocTestGetter, UnitDocTestGetter,
+ SimpleDocTestGetter]
class TestCollector(BasicTestCollector):
"""A TestCollector that wraps doctests and PythonTests.
"""
handled_getters = [FunctionalDocTestGetter, UnitDocTestGetter,
- PythonTestGetter]
+ PythonTestGetter, SimpleDocTestGetter]
Modified: z3c.testsetup/trunk/src/z3c/testsetup/nozopeapptesting.txt
===================================================================
--- z3c.testsetup/trunk/src/z3c/testsetup/nozopeapptesting.txt 2009-01-07 16:03:12 UTC (rev 94594)
+++ z3c.testsetup/trunk/src/z3c/testsetup/nozopeapptesting.txt 2009-01-07 16:08:23 UTC (rev 94595)
@@ -45,6 +45,7 @@
>>> from pprint import pprint
>>> pprint(sorted([str(x) for x in tc]))
["<class 'z3c.testsetup.testgetter.PythonTestGetter'>",
+ "<class 'z3c.testsetup.testgetter.SimpleDocTestGetter'>",
"<class 'z3c.testsetup.testgetter.UnitDocTestGetter'>"]
What is missing here, is the FunctionalDocTestGetter that normally
@@ -80,4 +81,5 @@
>>> pprint(sorted([str(x) for x in tc]))
["<class 'z3c.testsetup.functional.testgetter.FunctionalDocTestGetter'>",
"<class 'z3c.testsetup.testgetter.PythonTestGetter'>",
+ "<class 'z3c.testsetup.testgetter.SimpleDocTestGetter'>",
"<class 'z3c.testsetup.testgetter.UnitDocTestGetter'>"]
Modified: z3c.testsetup/trunk/src/z3c/testsetup/pythontestsetup.txt
===================================================================
--- z3c.testsetup/trunk/src/z3c/testsetup/pythontestsetup.txt 2009-01-07 16:03:12 UTC (rev 94594)
+++ z3c.testsetup/trunk/src/z3c/testsetup/pythontestsetup.txt 2009-01-07 16:08:23 UTC (rev 94595)
@@ -97,11 +97,12 @@
3) contain a ReStructured Text meta-marker in the module docstring,
that declares the module as a unittest module explicitly::
- :Test-Layer: python
+ :unittest:
This means: there *must* be a line like the above one in the
docstring of an accepted module. The term might be preceeded or
- followed by whitspace characters (spaces, tabs).
+ followed by whitspace characters (spaces, tabs) or a restructured
+ text comment marker (leading ``.. ``).
The docstring of a module is written at the module header like
this::
@@ -109,12 +110,19 @@
"""
This module smashes problems.
- :Test-Layer: python
+ :unittest:
"""
[normal Python code...]
+ .. note:: The ``:Test-Layer: python`` marker is deprecated.
+ In former releases of `z3c.testsetup` the mentioned marker was
+ used to mark unittests. This changed with version 0.3 and the
+ old marker is now deprecated (while still supported for some
+ limited time).
+
+
Only files, that meet all three conditions are searched for tests.
You can modify this behaviour of course, which will be explained below
in detail.
@@ -162,7 +170,7 @@
additional checking. Namely it checks for the existance of the above
mentioned ReStructured Text meta-marker::
- `:Test-Layer: python`
+ `:unittest:`
This marker is determined by a list of regular expressions, which is
also available as an object attribute::
Modified: z3c.testsetup/trunk/src/z3c/testsetup/testgetter.py
===================================================================
--- z3c.testsetup/trunk/src/z3c/testsetup/testgetter.py 2009-01-07 16:03:12 UTC (rev 94594)
+++ z3c.testsetup/trunk/src/z3c/testsetup/testgetter.py 2009-01-07 16:08:23 UTC (rev 94595)
@@ -20,7 +20,7 @@
See testgetter.txt to learn more about this stuff.
"""
import unittest
-from z3c.testsetup.doctesting import UnitDocTestSetup
+from z3c.testsetup.doctesting import UnitDocTestSetup, SimpleDocTestSetup
from z3c.testsetup.testing import UnitTestSetup
from z3c.testsetup.util import get_package, get_keyword_params
@@ -98,6 +98,12 @@
return self.__call__()
+class SimpleDocTestGetter(BasicTestGetter):
+ """Collect simple unit doctests.
+ """
+ wrapped_class = SimpleDocTestSetup
+ special_char = 'd'
+
class UnitDocTestGetter(BasicTestGetter):
"""Collect unit doctests.
"""
@@ -140,10 +146,11 @@
class DocTestCollector(BasicTestCollector):
"""A TestCollector that wraps unit doctests.
"""
- handled_getters = [UnitDocTestGetter,]
+ handled_getters = [UnitDocTestGetter, SimpleDocTestGetter]
class TestCollector(BasicTestCollector):
"""A TestCollector that wraps doctests and PythonTests.
"""
- handled_getters = [UnitDocTestGetter, PythonTestGetter]
+ handled_getters = [SimpleDocTestGetter,
+ UnitDocTestGetter, PythonTestGetter]
Modified: z3c.testsetup/trunk/src/z3c/testsetup/testgetter.txt
===================================================================
--- z3c.testsetup/trunk/src/z3c/testsetup/testgetter.txt 2009-01-07 16:03:12 UTC (rev 94594)
+++ z3c.testsetup/trunk/src/z3c/testsetup/testgetter.txt 2009-01-07 16:08:23 UTC (rev 94595)
@@ -103,14 +103,15 @@
>>> getter_classes
[<class '....FunctionalDocTestGetter'>,
<class '....UnitDocTestGetter'>,
- <class '....PythonTestGetter'>]
+ <class '....PythonTestGetter'>,
+ <class '....SimpleDocTestGetter'>]
Each of this classes should provide a 'signature char'. This is stored
as the ``special_char`` attribute of a ``TestGetter`` class::
>>> [(x.__name__, x.special_char) for x in getter_classes]
[('FunctionalDocTestGetter', 'f'), ('UnitDocTestGetter', 'u'),
- ('PythonTestGetter', 'p')]
+ ('PythonTestGetter', 'p'), ('SimpleDocTestGetter', 'd')]
As we can see, functional doc test parameters are marked with a
preceeding `f`. So we use 'fextensions' to mark the 'extensions'
Modified: z3c.testsetup/trunk/src/z3c/testsetup/testing.py
===================================================================
--- z3c.testsetup/trunk/src/z3c/testsetup/testing.py 2009-01-07 16:03:12 UTC (rev 94594)
+++ z3c.testsetup/trunk/src/z3c/testsetup/testing.py 2009-01-07 16:08:23 UTC (rev 94595)
@@ -17,7 +17,8 @@
import re
from martian.scan import module_info_from_dotted_name
from z3c.testsetup.base import BasicTestSetup
-from z3c.testsetup.util import get_package
+from z3c.testsetup.util import (get_package, get_marker_from_string,
+ get_marker_from_file)
class UnitTestSetup(BasicTestSetup):
"""A unit test setup for packages.
@@ -38,10 +39,11 @@
regexp_list = [
'^\s*:(T|t)est-(L|l)ayer:\s*(python)\s*',
]
-
+
def __init__(self, package, pfilter_func=None, regexp_list=None):
BasicTestSetup.__init__(self, package, regexp_list=regexp_list)
self.pfilter_func = pfilter_func or self.isTestModule
+ self.filter_func = self.pfilter_func
def docstrContains(self, docstr, regexp_list):
"""Does a docstring contain lines matching every of the regular
@@ -50,6 +52,8 @@
found_list = []
if docstr is None:
return False
+ if get_marker_from_string('unittest', docstr) is not None:
+ return True
for line in docstr.split('\n'):
for regexp in regexp_list:
if re.compile(regexp).match(line) and (
@@ -69,7 +73,8 @@
# Do not even try to load modules, that have no marker string.
if not self.fileContains(
module_info.path, self.regexp_list):
- return False
+ if get_marker_from_file('unittest', module_info.path) is None:
+ return False
module = None
try:
module = module_info.getModule()
Copied: z3c.testsetup/trunk/src/z3c/testsetup/tests/README_OLD.txt (from rev 94594, z3c.testsetup/branches/new_markers/src/z3c/testsetup/tests/README_OLD.txt)
===================================================================
--- z3c.testsetup/trunk/src/z3c/testsetup/tests/README_OLD.txt (rev 0)
+++ z3c.testsetup/trunk/src/z3c/testsetup/tests/README_OLD.txt 2009-01-07 16:08:23 UTC (rev 94595)
@@ -0,0 +1,537 @@
+z3c.testsetup
+*************
+
+.. warning:: THIS IS OUTDATED STUFF
+
+ The tests in here exist only to check for compatibility with
+ former releases.
+
+ The methods and markers herein are mostly deprecated, subject to
+ change or vanish completely and should not be used any more.
+
+ See `README.txt` in the parent directory for up-to-date
+ information.
+
+Easy testsetups for Zope 3 and Python projects.
+
+Setting up tests for Zope 3 projects sometimes tends to be
+cumbersome. ``z3c.testsetup`` jumps in here, to support much flatter
+test setups. The package supports three kinds of tests:
+
+- normal python tests: i.e. tests, that consist of python modules
+ which in turn contain ``unittest.TestCase`` classes.
+
+- unit doctests: i.e. tests, that are written as doctests, but require
+ no complicated layer setup etc.
+
+- functional doctests: i.e. tests, that are written as doctests, but
+ also require a more or less complex framework to test for example
+ browser requests.
+
+``z3c.testsetup`` is package-oriented. That means, it registers more or
+less automatically all the three kinds of tests mentioned above
+insofar they are part of a certain package.
+
+This is a general introduction to ``z3c.testsetup``. For setup
+examples you might see the ``cave`` package contained in the `tests/`
+directory. More details on special topics can be found in the
+appropriate .txt files in this directory.
+
+
+Basic Example
+=============
+
+The shortest test setup possible with ``z3c.testsetup`` looks like
+this::
+
+ >>> import z3c.testsetup
+ >>> test_suite = z3c.testsetup.register_all_tests(
+ ... 'z3c.testsetup.tests.cave')
+
+It is sufficient to put this lines into a python module which is found
+by your testrunner (see `samplesetup_short` examples in the ``cave``
+package and ``testrunner.txt``).
+
+To sum it up, testsetup with ``z3c.testsetup`` is done in two steps:
+
+1) Make sure your testfiles are named properly (.txt/.rst for
+ doctests, valid python modules for usual unit tests) and provide a
+ suitable marker string as explained below (`How to mark
+ testfiles/modules`_).
+
+2) Write a test setup module which is named so that your testrunner
+ finds it and in this module call::
+
+ test_suite = z3c.testsetup.register_all_tests(<package>)
+
+ where ``<package>`` must be a package object. Instead of a package
+ object you can also pass the package's dotted name as string like
+ `'z3c.testsetup.tests.cave'`.
+
+Given that, this setup should find all doctests (unit and functional)
+as well as python tests in the package and register them.
+
+
+Customized Setups
+=================
+
+The `register_all_tests` function mentioned above accepts a bunch of
+keyword parameters::
+
+ register_all_tests(pkg_or_dotted_name, filter_func, extensions,
+ encoding, checker,
+ globs, setup, teardown, optionflags
+ zcml_config, layer_name, layer)
+
+where all but the first parameter are keyword paramters and all but
+the package parameter are optional.
+
+While `filter_func` and `extensions` determine the set of testfiles to
+be found, the other paramters tell how to setup single tests.
+
+
+- **filter_func** (**ufilter_func**, **ffilter_func**)
+
+ a function that takes an absolute filepath and returns `True` or
+ `False`, depending on whether the file should be included in the
+ test suite as doctest or not. `filter_func` applies only to
+ doctests.
+
+ We setup a few things to check that::
+
+ >>> import os
+ >>> import unittest
+ >>> suite = test_suite()
+ >>> suite.countTestCases()
+ 4
+
+ Okay, the callable in `test_suite` we created above with
+ `register_all_tests` apparently delivered four testcases. This is
+ normally also the number of files involved, but let's check that
+ correctly.
+
+ We did setup a function `get_basenames_from_suite` in this testing
+ environment (as a `globs` entry) which determines the basenames of
+ the paths of all testcases contained in a `TestSuite`::
+
+ >>> get_basenames_from_suite(suite)
+ ['file1.py', 'file1.rst', 'file1.txt', 'subdirfile.txt']
+
+ Ah, okay. There are in fact four files, in which testcases were
+ found. Now, we define a plain filter function::
+
+ >>> def custom_file_filter(path):
+ ... """Accept all txt files."""
+ ... return path.endswith('.txt')
+
+ This one accepts all '.txt' files. We run `register_all_tests`
+ again, but this time with a `filter_func` parameter::
+
+ >>> test_suite = z3c.testsetup.register_all_tests(
+ ... 'z3c.testsetup.tests.cave',
+ ... filter_func=custom_file_filter)
+
+ To get the resulting test suite, we again call the returned
+ callable::
+
+ >>> suite = test_suite()
+ >>> get_basenames_from_suite(suite)
+ ['file1.py', 'file1.txt', 'file1.txt', 'file1.txt', 'subdirfile.txt',
+ 'subdirfile.txt', 'subdirfile.txt']
+
+ Compared with the first call to `register_all_tests` we got some
+ strange results here: there is a '.py' file, which should have been
+ refused by our filter function and the other two files appear
+ twice. What happened?
+
+ The python module is included, because python tests are not
+ filtered by `filter_func`. Instead this value applies only to
+ doctests.
+
+ The second strange result, that every .txt file appears twice in
+ the list, comes from the fact, that the filter is valid for unit
+ and functional doctests at the same time. In other words: the tests
+ in those .txt files are registered twice, as unittests and a second
+ time as functional tests as well.
+
+ If you want a filter function for functional doctests or unit
+ doctests only, then you can use `ffilter_func` and `ufilter_func`
+ respectively::
+
+ >>> test_suite = z3c.testsetup.register_all_tests(
+ ... 'z3c.testsetup.tests.cave',
+ ... ffilter_func=custom_file_filter,
+ ... ufilter_func=lambda x: False)
+
+ >>> suite = test_suite()
+ >>> get_basenames_from_suite(suite)
+ ['file1.py', 'file1.txt', 'subdirfile.txt']
+
+ As expected, every .txt file was only registered once. The same
+ happens, when we switch and accept only unit doctests::
+
+ >>> test_suite = z3c.testsetup.register_all_tests(
+ ... 'z3c.testsetup.tests.cave',
+ ... ffilter_func=lambda x: False,
+ ... ufilter_func=custom_file_filter)
+
+ >>> suite = test_suite()
+ >>> get_basenames_from_suite(suite)
+ ['file1.py', 'file1.txt', 'subdirfile.txt']
+
+ If you specify both, a `filter_func` and a more specialized
+ `ufilter_func` or `ffilter_func`, then this has the same effect as
+ passing both, `ufilter_func` and `ffilter_func`::
+
+ >>> test_suite = z3c.testsetup.register_all_tests(
+ ... 'z3c.testsetup.tests.cave',
+ ... ffilter_func=lambda x: False,
+ ... filter_func=custom_file_filter)
+
+ >>> suite = test_suite()
+ >>> get_basenames_from_suite(suite)
+ ['file1.py', 'file1.txt', 'file1.txt', 'subdirfile.txt',
+ 'subdirfile.txt']
+
+
+- **pfilter_func**:
+
+ Does basically the same as the ``filter_funcs`` above, but handles
+ Python modules instead of file paths. It therefore determines the
+ set of 'normal' Python tests accepted and does not touch the set
+ of doctests accepted.
+
+ We define a simple custom filter::
+
+ >>> def custom_module_filter(module_info):
+ ... return 'Tests with real' in open(module_info.path, 'r').read()
+
+ that checks for a certain string in modules' doc strings.
+
+ Now we start again with `pfilter_func` set::
+
+ >>> test_suite = z3c.testsetup.register_all_tests(
+ ... 'z3c.testsetup.tests.cave',
+ ... pfilter_func=custom_module_filter)
+ >>> suite = test_suite()
+ >>> get_basenames_from_suite(suite)
+ ['file1.py', 'file1.rst', 'file1.txt', 'notatest2.py', 'subdirfile.txt']
+
+ Because file1.py and notatest2.py in the cave package contain the
+ required string, this is correct. Because the default function
+ checks for the string `:Test-Layer: python`, the second module was
+ omitted by default.
+
+ Now let's use a filter, that refuses all modules::
+
+ >>> test_suite = z3c.testsetup.register_all_tests(
+ ... 'z3c.testsetup.tests.cave',
+ ... pfilter_func=lambda x: False)
+ >>> suite = test_suite()
+ >>> get_basenames_from_suite(suite)
+ ['file1.rst', 'file1.txt', 'subdirfile.txt']
+
+ All Python modules vanished from the list.
+
+ In case you wonder, why not all the other Python files of the
+ `cave` package (`__init__.py`, for example) appear in one of the
+ lists: we get only the result list, which contains only such
+ modules, which provide `unittest.TestCase` definitions. Because
+ most modules of the `cave` package don't define test cases, they
+ do not appear in the list. This automatism is driven by a
+ `unittest.TestLoader`. See
+ http://docs.python.org/lib/testloader-objects.html to learn more
+ about test loaders.
+
+
+- **extensions** (**uextensions**, **fextensions**):
+
+ a list of filename extensions to be considered during test
+ search. Default value is `['.txt', '.rst']`. Python tests are not
+ touched by this (they have to be regular Python modules with '.py'
+ extension).
+
+ Note, that the `extensions` attribute is used by the default
+ filter function. If you pass your own filter function using
+ `[u|f]filter_func`, then the extensions filtering won't work any
+ more.
+
+ If we want to register .foo files, we can do so::
+
+ >>> test_suite = z3c.testsetup.register_all_tests(
+ ... 'z3c.testsetup.tests.cave',
+ ... extensions=['.foo'])
+ >>> suite = test_suite()
+ >>> get_basenames_from_suite(suite)
+ ['file1.py', 'notatest1.foo', 'notatest1.foo']
+
+ Note, that only files that contain an appropriate marker are
+ found, regardless of the filename extension. The new .foo file
+ contains a marker for unit doctests and functional doctests, such
+ it is included twice in the list.
+
+ As we can see, the new file appears twice. This is, because it is
+ registered as functional doctest and unitdoctest as well.
+
+ To collect only functional doctests with a certain set of filename
+ extensions you can use: `fextensions`::
+
+ >>> test_suite = z3c.testsetup.register_all_tests(
+ ... 'z3c.testsetup.tests.cave',
+ ... fextensions=['.foo'])
+ >>> suite = test_suite()
+ >>> get_basenames_from_suite(suite)
+ ['file1.py', 'file1.rst', 'notatest1.foo']
+
+ Here the .rst file were registered as unit doctest, while the .foo
+ file was registered as functional doctest.
+
+ To collect only unit doctests with a different set of filename
+ extensions you can use `uextensions`::
+
+ >>> test_suite = z3c.testsetup.register_all_tests(
+ ... 'z3c.testsetup.tests.cave',
+ ... uextensions=['.foo'])
+ >>> suite = test_suite()
+ >>> get_basenames_from_suite(suite)
+ ['file1.py', 'file1.txt', 'notatest1.foo', 'subdirfile.txt']
+
+ Here the .foo file was registered as unit doctest and the .txt
+ files as functional ones.
+
+
+- **encoding**:
+
+ the encoding of testfiles. 'utf-8' by default. Setting this to `None`
+ means using the default value. We've hidden one doctest file, that
+ contains umlauts. If we set the encoding to `ascii`, we get an
+ error::
+
+ >>> test_suite = z3c.testsetup.register_all_tests(
+ ... 'z3c.testsetup.tests.cave',
+ ... encoding='ascii')
+ >>> suite = test_suite()
+ Traceback (most recent call last):
+ ...
+ UnicodeDecodeError: 'ascii' codec can't decode ...: ordinal
+ not in range(128)
+
+ While using 'latin-1' will work::
+
+ >>> test_suite = z3c.testsetup.register_all_tests(
+ ... 'z3c.testsetup.tests.cave',
+ ... encoding='latin-1')
+ >>> suite = test_suite()
+
+ No traceback here.
+
+ You can always overwrite an encoding setting for a certain file by
+ following PEP 0263 ( http://www.python.org/dev/peps/pep-0263/ ).
+
+
+- **checker**:
+
+ An output checker for functional doctests. `None` by default. A
+ typical output checker can be created like this::
+
+ >>> import re
+ >>> 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>'),
+ ... ])
+
+ This would match for example output like `0.123 seconds` if you
+ write in your doctest::
+
+ <SOME NUBMER OF> seconds
+
+ Please see ``testrunner.txt`` for examples of usage.
+
+ Checkers are applied to functional doctests only!
+
+- **globs**:
+
+ A dictionary of things that should be available immediately
+ (without imports) during tests. Defaults are::
+
+ dict(http=HTTPCaller(),
+ getRootFolder=getRootFolder,
+ sync=sync)
+
+ for functional doctests and an empty dict for unit
+ doctests. Python test globals can't be set this way.
+
+ If you want to register special globals for functional doctest or
+ unit doctests only, then you can use the `fglobs` and/or `uglobs`
+ keyword respectively. These keywords replace any `globs` value for
+ the respective kind of tests.
+
+ For more extensive examples see ``testrunner.txt``.
+
+- **setup**:
+
+ A function that takes a `test` argument and is executed before
+ every single doctest. By default it runs::
+
+ zope.app.testing.functional.FunctionalTestSetup().setUp()
+
+ for functional doctests and an empty function for unit
+ doctests. Python tests provide their own setups.
+
+ If you want to register special setup-functions for either
+ functional or unit doctests, then you can pass keyword parameters
+ `fsetup` or `usetup` respectively.
+
+- **teardown**:
+
+ The equivalent to `setup`. Runs by default::
+
+ FunctionalTestSetup().tearDown()
+
+ for functional doctests and::
+
+ zope.testing.cleanup.cleanUp()
+
+ for unit doctests. Python tests have to provide their own teardown
+ functions in TestCases.
+
+- **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.
+
+- **zcml_config**:
+
+ A filepath of a ZCML file which is registered with functional
+ doctests. In the ZCML file you can for example register principals
+ (users) usable by functional doctests.
+
+ By default any `ftesting.zcml` file from the root of the given
+ package is taken. If this does not exist, an empty ZCML file of
+ the z3c.testsetup package is used (``ftesting.zcml``).
+
+ This parameter has no effect, if also a ``layer`` parameter is
+ given.
+
+- **layer_name**:
+
+ You can name your layer, to distinguish different setups of
+ functional doctests. The layer name can be an arbitrary string.
+
+ This parameter has no effect, if also a ``layer`` parameter is
+ given.
+
+- **layer**:
+
+ You can register a ZCML layer yourself and pass it as the
+ ``layer`` parameter. If you only have a filepath to the according
+ ZCML file, use the ``zcml_config`` paramter instead.
+
+ This parameter overrides any ``zcml_config`` and ``layer_name``
+ parameter.
+
+
+How to mark testfiles/modules
+=============================
+
+To avoid non-wanted files and modules to be registered, you have to
+mark your wanted test files/modules with a special string explicitly:
+
+- python modules you want to register must provide a module docstring
+ that contains a line::
+
+ :Test-Layer: python
+
+ A module doctring is written at the top of file like this:
+
+ **Python Unit Test Example:**::
+
+ """
+ A module that tests things.
+
+ :Test-Layer: python
+
+ """
+ import unittest
+ class MyTest(unittest.TestCase):
+ def testFoo(self):
+ pass
+
+
+- doctest files that contain unit tests must provide a string::
+
+ :Test-Layer: unit
+
+ to be registered. Futhermore, their filename extension must be by
+ default '.txt' or '.rst'. A file `sampletest.txt` with a unit
+ doctest therefore might look like this:
+
+ **Unit Doctest Example 1:**::
+
+ ==========
+ My package
+ ==========
+
+ :Test-Layer: unit
+
+ This is documentation for the MyPackage package.
+
+ >>> 1+1
+ 2
+
+ Also python modules which contain tests in doctests notation are
+ doctests. As rule of thumb you can say: if a module contains tests
+ that are written preceeded by '>>>', then this is a doctest. If
+ ``unittest.TestCase`` classes are defined, then it is a 'normal'
+ python testfile. Another valid unit doctest module therefore can
+ look like this:
+
+ **Unit Doctest Example 2:**::
+
+ """
+ ==========
+ My package
+ ==========
+
+ A package for doing things.
+
+ :Test-Layer: unit
+
+ We check for basic things::
+
+ >>> 1+1
+ 2
+
+ """
+ class MyClass:
+ pass
+
+
+- files that contain functional doctests must provide a string::
+
+ :Test-Layer: functional
+
+ to be registered. Furthermore they must by default have a filename
+ extension `.txt` or `.rst`. A file `sampletest.txt` with functional
+ tests might look like this:
+
+ **Functional Doctest Example:**::
+
+ ==========
+ My package
+ ==========
+
+ :Test-Layer: functional
+
+ This is documentation for the MyPackage package.
+
+ >>> 1+1
+ 2
+
+
Modified: z3c.testsetup/trunk/src/z3c/testsetup/tests/test_testsetup.py
===================================================================
--- z3c.testsetup/trunk/src/z3c/testsetup/tests/test_testsetup.py 2009-01-07 16:03:12 UTC (rev 94594)
+++ z3c.testsetup/trunk/src/z3c/testsetup/tests/test_testsetup.py 2009-01-07 16:08:23 UTC (rev 94595)
@@ -13,6 +13,7 @@
'pythontestsetup.txt', 'unitdoctestsetup.txt', 'util.txt',
'unittestsetup.txt',
os.path.join('tests', 'setupininit.txt'),
+ os.path.join('tests', 'util.txt'),
]
def pnorm(path):
@@ -48,8 +49,16 @@
basenames = [os.path.basename(x) for x in get_filenames_from_suite(suite)]
basenames.sort()
return basenames
-
+def print_file(path):
+ """Prints file contents with leading bar on each line.
+
+ This way we prevent the testrunner to test the output.
+ """
+ contents = open(path, 'r').read()
+ print '| ' + '\n| '.join(contents.split('\n'))
+ return
+
def setUpZope(test):
zope.component.eventtesting.setUp(test)
@@ -69,6 +78,7 @@
test.globs['this_directory'] = os.path.split(__file__)[0]
test.globs['testrunner_script'] = __file__
test.globs['get_basenames_from_suite'] = get_basenames_from_suite
+ test.globs['print_file'] = print_file
def tearDown(test):
sys.path[:], sys.argv[:] = test.globs['saved-sys-info'][:2]
@@ -77,7 +87,7 @@
sys.modules.update(test.globs['saved-sys-info'][2])
suites = [
doctest.DocFileSuite(
- 'README.txt', 'testgetter.txt', 'testrunner.txt',
+ 'tests/README_OLD.txt', 'testgetter.txt', 'testrunner.txt', 'README.txt',
package='z3c.testsetup',
setUp=setUp, tearDown=tearDown,
optionflags=doctest.ELLIPSIS+doctest.NORMALIZE_WHITESPACE,
@@ -133,7 +143,8 @@
tearDown=cleanUpZope,
globs={'pnorm':pnorm,
'get_basenames_from_suite':
- get_basenames_from_suite},
+ get_basenames_from_suite,
+ 'print_file':print_file,},
checker=checker,
optionflags=doctest.ELLIPSIS+
doctest.NORMALIZE_WHITESPACE)
Copied: z3c.testsetup/trunk/src/z3c/testsetup/tests/util.txt (from rev 94594, z3c.testsetup/branches/new_markers/src/z3c/testsetup/tests/util.txt)
===================================================================
--- z3c.testsetup/trunk/src/z3c/testsetup/tests/util.txt (rev 0)
+++ z3c.testsetup/trunk/src/z3c/testsetup/tests/util.txt 2009-01-07 16:08:23 UTC (rev 94595)
@@ -0,0 +1,68 @@
+Tests for helper functions
+**************************
+
+In the ``util`` module we provide some helpers.
+
+utils.get_marker_from_string(marker, text)
+==========================================
+
+Gets us the first occurence of a line in ``text``, which is headed by
+a marker string ``marker``::
+
+ >>> from z3c.testsetup.util import get_marker_from_string
+ >>> text = """
+ ... My File
+ ...
+ ... :mymarker: blah
+ ... """
+ >>> get_marker_from_string('mymarker', text)
+ u'blah'
+
+The marker is also found in the first line::
+
+ >>> text = """:mymarker: blah"""
+ >>> get_marker_from_string('mymarker', text)
+ u'blah'
+
+When several same-named markers occur, the first one is picked::
+
+ >>> text = """
+ ... :mymarker: blah
+ ... :mymarker: blubb
+ ... """
+ >>> get_marker_from_string('mymarker', text)
+ u'blah'
+
+The lookup is case insensitive while the result is not::
+
+ >>> text = """
+ ... :MyMarker: Blah
+ ... """
+ >>> get_marker_from_string('mymarker', text)
+ u'Blah'
+
+We also accept marker strings preceeded by two dot followed by
+whitespaces (a comment in restructured text)::
+
+ >>> text = """
+ ... .. :MyMarker: Blah
+ ... """
+ >>> get_marker_from_string('mymarker', text)
+ u'Blah'
+
+When the marker string cannot be found, ``None`` is returned::
+
+ >>> text = """
+ ... :NotMyMarker: Blah
+ ... """
+ >>> get_marker_from_string('mymarker', text) is None
+ True
+
+Also other chars preceeding the marker string are not allowed::
+
+ >>> text = """
+ ... garbage :MyMarker: Blah
+ ... """
+ >>> get_marker_from_string('mymarker', text) is None
+ True
+
Modified: z3c.testsetup/trunk/src/z3c/testsetup/unittestsetup.txt
===================================================================
--- z3c.testsetup/trunk/src/z3c/testsetup/unittestsetup.txt 2009-01-07 16:03:12 UTC (rev 94594)
+++ z3c.testsetup/trunk/src/z3c/testsetup/unittestsetup.txt 2009-01-07 16:08:23 UTC (rev 94595)
@@ -105,19 +105,24 @@
that defines the module as a testing module
explicitly::
- :Test-Layer: python
+ :unittest:
This means: there *must* be a line like the above one in the
docstring of the module (not: docstring of a class or function
therein). The term might be preceeded or followed by whitspace
characters (spaces, tabs).
+ .. note:: What about ``:Test-Layer: python``?
+
+ This marker was used in former releases of ``z3c.testsetup``. It
+ currently still works but is deprecated now.
+
For example a module `example.py` would be found if it contains::
"""
Tests to foo.
- :Test-Layer: python
+ :unittest:
"""
import unittest
@@ -145,16 +150,8 @@
The unit test setup requires that files contain the above mentioned
ReStructured Text meta-marker::
- `:Test-Layer: unit`
+ `:unittest:`
-in their module docstring. This is determined by a list of regular
-expressions, which is also available as an object attribute::
-
- >>> setup.regexp_list
- ['^\\s*:(T|t)est-(L|l)ayer:\\s*(python)\\s*']
-
-This is the default value of unit test setups.
-
There is one file in the `cave` subpackage, which includes that
marker. We can get the list of test files using
`getTestFiles()``::
Modified: z3c.testsetup/trunk/src/z3c/testsetup/util.py
===================================================================
--- z3c.testsetup/trunk/src/z3c/testsetup/util.py 2009-01-07 16:03:12 UTC (rev 94594)
+++ z3c.testsetup/trunk/src/z3c/testsetup/util.py 2009-01-07 16:08:23 UTC (rev 94595)
@@ -13,6 +13,8 @@
##############################################################################
"""Helper functions for testsetup.
"""
+import sys
+import re
from inspect import getmro, ismethod, getargspec
from martian.scan import resolve
@@ -58,13 +60,20 @@
Returns the found value or `None`. A markerstring has the form::
:<Tag>: <Value>
+
+ or
+
+ .. :<Tag>: <Value>
+
"""
marker = ":%s:" % marker.lower()
+ rexp = re.compile('^(\.\.\s+)?%s(.*)$' % (marker,), re.IGNORECASE)
for line in text.split('\n'):
line = line.strip()
- if not line.lower().startswith(marker):
+ result = rexp.match(line)
+ if result is None:
continue
- result = line[len(marker):].strip()
+ result = result.groups()[1].strip()
return unicode(result)
return None
@@ -76,5 +85,17 @@
:<Tag>: <Value>
"""
- return get_marker_from_string(marker, open(filepath, 'r').read())
+ return get_marker_from_string(marker, open(filepath, 'rb').read())
+def warn(text):
+ print "Warning: ", text
+
+def import_name(name):
+ __import__(name)
+ return sys.modules[name]
+
+def get_attribute(name):
+ name, attr = name.rsplit('.', 1)
+ obj = import_name(name)
+ return getattr(obj, attr)
+
More information about the Checkins
mailing list