Skip to content

Commit

Permalink
Added doctestcase.doctestfiles
Browse files Browse the repository at this point in the history
  - Define multiple doctest files at once.

  - Automatically assign test class members.  So rather than::

      test_foo = doctestcase.doctestfile('foo.txt')

    You can use::

      doctestcase.doctestfiles('foo.txt')
  • Loading branch information
Jim Fulton committed Aug 31, 2015
1 parent 0402096 commit f03c227
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 14 deletions.
12 changes: 12 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,18 @@ Changes
The meta data us useful, for example, for selecting tests with the
nose attribute mechanism.

- Added ``doctestcase.doctestfiles``

- Define multiple doctest files at once.

- Automatically assign test class members. So rather than::

test_foo = doctestcase.doctestfile('foo.txt')

You can use::

doctestcase.doctestfiles('foo.txt')

4.4.0 (2015-07-16)
------------------

Expand Down
46 changes: 43 additions & 3 deletions src/zope/testing/doctestcase.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ def doctestfile(path, optionflags=0, checker=None):
If a test case defines a globs attribute, it must be a dictionary
and its contents are added to the test globals.
The test object is available as the variable ``self`` in the test.
The test object is available as the variable ``test`` in the test.
The resulting object can be used as a function decorator. The
decorated method is called before the test and may perform
Expand Down Expand Up @@ -220,15 +220,55 @@ def test_file_w_setup(self):

_run_test(self, test, {}, name, path, optionflags, checker, 'test')

test_file.__name__ = _testify(
_not_word.sub('_', os.path.splitext(os.path.basename(path))[0]))
test_file.__name__ = name_from_path(path)
test_file.filepath = path
test_file.filename = os.path.basename(path)

return test_file

file = doctestfile

def doctestfiles(*paths, **kw):
"""Define doctests from test files within a unittest.TestCase.
Multiple files can be specified. A member is added to the
surrounding class for each file.
The file paths may be relative or absolute. If relative (the
common case), they will be interpreted relative to the directory
containing the referencing module.
You can pass doctest option flags and a custon checker.
If a test case defines a globs attribute, it must be a dictionary
and its contents are added to the test globals.
The test object is available as the variable ``test`` in the test.
The resulting object can be used as a function decorator. The
decorated method is called before the test and may perform
test-specific setup. (The decorated method's doc string is ignored.)
"""
locals = sys._getframe(1).f_locals
for path in paths:
locals[name_from_path(path)] = doctestfile(path, **kw)

def doctestfiles_w_setup(func):
for path in paths:
name = name_from_path(path)
test = doctestfile(path, **kw)(func)
locals[name] = test
test.__name__ = name

return doctestfiles_w_setup

files = doctestfiles

def name_from_path(path):
return _testify(
_not_word.sub('_', os.path.splitext(os.path.basename(path))[0])
)

def _run_test(self, test, globs, name, path,
optionflags, checker, testname='self', lineno=0):
globs.update(getattr(self, 'globs', ()))
Expand Down
101 changes: 90 additions & 11 deletions src/zope/testing/doctestcase.txt
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ Here are some examples::
... @doctestcase.doctestfile('test4.txt')
... def test4(self):
... self.x = 5
...
... doctestcase.doctestfiles('loggingsupport.txt', 'renormalizing.txt')

.. We can run these tests with the ``unittest`` test runner.

Expand All @@ -66,6 +68,8 @@ Here are some examples::
test2 (tests.MyTest) ... ok
test3 (tests.MyTest) ... ok
test4 (tests.MyTest) ... ok
test_loggingsupport (tests.MyTest) ... FAIL
test_renormalizing (tests.MyTest) ... FAIL


>>> for _, e in result.errors:
Expand Down Expand Up @@ -93,8 +97,70 @@ Here are some examples::
>>> MyTest.test4.filename
'test4.txt'

>>> MyTest.test_loggingsupport.__name__
'test_loggingsupport'
>>> MyTest.test_loggingsupport.filename
'loggingsupport.txt'
>>> (MyTest.test_loggingsupport.filepath ==
... os.path.join(os.path.dirname(zope.testing.__file__),
... 'loggingsupport.txt'))
True

In this example, 3 constructors were used:
Need setup:

>>> import sys
>>> class MyTest(unittest.TestCase):
...
... def setUp(self):
... self.a = 1
... self.globs = dict(c=9)
...
... test1 = doctestcase.file('test-1.txt', optionflags=doctest.ELLIPSIS)
...
... test2 = doctestcase.docteststring('''
... >>> self.a, g, c
... (1, 'global', 9)
... ''')
...
... @doctestcase.doctestmethod(optionflags=doctest.ELLIPSIS)
... def test3(self):
... '''
... >>> self.a, self.x, g, c
... (1, 3, 'global', 9)
... '''
... self.x = 3
...
... @doctestcase.doctestfile('test4.txt')
... def test4(self):
... self.x = 5
...
... @doctestcase.files('loggingsupport.txt', 'renormalizing.txt')
... def setup_print(self):
... def print_(*args):
... sys.stdout.write(' '.join(map(str, args))+'\n')
... self.globs['print_'] = print_

>>> suite = loader.loadTestsFromTestCase(MyTest)
>>> result = suite.run(unittest.TextTestResult(sys.stdout, True, 3))
test1 (tests.MyTest) ... ok
test2 (tests.MyTest) ... ok
test3 (tests.MyTest) ... ok
test4 (tests.MyTest) ... ok
test_loggingsupport (tests.MyTest) ... ok
test_renormalizing (tests.MyTest) ... ok

Check meta data with setup function:

>>> MyTest.test_loggingsupport.__name__
'test_loggingsupport'
>>> MyTest.test_loggingsupport.filename
'loggingsupport.txt'
>>> (MyTest.test_loggingsupport.filepath ==
... os.path.join(os.path.dirname(zope.testing.__file__),
... 'loggingsupport.txt'))
True

In this example, 4 constructors were used:

doctestfile (alias: file)
doctestfile makes a file-based test case.
Expand All @@ -103,6 +169,16 @@ doctestfile (alias: file)
function is called before the test is run, to provide test-specific
setup.

doctestfiles (alias: files)
doctestfiles makes file-based test cases and assigns them to the class.

Multile files can be specified and the resulting doctests are inserted into
the class dictionary.

This can be used as a decorator, in which case, the decorated
function is called before each test is run, to provide test-specific
setup.

docteststring (alias string)
docteststring constructs a doctest from a string.

Expand All @@ -125,8 +201,9 @@ Tests have access to the following data:
constructors, the test case instance is available as the ``self``
variable.

- In tests created with the ``doctestfile`` constructor, the test case
instance is available as the ``test`` variable.
- In tests created with the ``doctestfile`` and ``doctestfiles``
constructor, the test case instance is available as the ``test``
variable.

- If a test case defines a globs attribute, it must be a dictionary
and it's contents are added to the test globals.
Expand All @@ -137,8 +214,9 @@ The constructors accept standard doctest ``optionflags`` and
Note that the doctest IGNORE_EXCEPTION_DETAIL option flag is
added to optionflags.

When using ``doctestfile``, ``filename`` and ``filepath`` attributes
are available that contain the test file name and full path.
When using ``doctestfile`` and ``doctestfile``, ``filename`` and
``filepath`` attributes are available that contain the test file name
and full path.

``__name__`` attributes of class members
----------------------------------------
Expand All @@ -149,12 +227,13 @@ Class members have ``__name__`` attributes set as follows:
function, ``__name__`` attribute is set to the name of the function.
A ``test_`` prefix is added, if the name doesn't start with ``test``.

- When doctestfile is used without a setup function, ``__name__`` is
set to the last part of the file path with the extension removed and
non-word characters converted to underscores. For example, with a
test path of ``'/foo/bar/test-it.rst'``, the ``__name__`` attribute
is set to ``'test_it'``. A ``test_`` prefix is added, if the name
doesn't start with ``test``.
- When ``doctestfile`` is used without a setup function or when
``doctestfiles`` is used, ``__name__`` is set to the last part of the
file path with the extension removed and non-word characters
converted to underscores. For example, with a test path of
``'/foo/bar/test-it.rst'``, the ``__name__`` attribute is set to
``'test_it'``. A ``test_`` prefix is added, if the name doesn't
start with ``test``.

- when using ``docteststring``, a ``name`` option can be passed in to
set ``__name__``. A ``test_`` prefix is added, if the name doesn't
Expand Down

0 comments on commit f03c227

Please sign in to comment.