[TIP] Fwd: An OO API for doctest / unittest integration...

Olemis Lang olemis at gmail.com
Fri Sep 12 07:37:53 PDT 2008


2008/9/8, Olemis Lang <olemis at gmail.com>:
> 2008/9/3, Olemis Lang <olemis at gmail.com>:
>
> >
>  > Release 0.1.2 is available now and it fixes these issues. You can
>  >  download it now and try it out.
>  >

This is old news already...

Recently I needed to load the tests defined across a package
hierarchy.  After looking at some tests written for standard modules I
realized that this could be useful to other people.

So I considered some ideas I heard before... (don't remember either where nbor
who mentionned the subject) for implementing the
class PackageTestLoader.  I also decided to include it in the module dutest.
It uses regular expressions so as to filter the modules from
where tests will be retrieved.  This class is based on the decorator
pattern [2]_ (Yes...  patterns, patterns and more patterns...  I love
patterns ;).  This means that you can use it together with other loader
which actually loads the tests from every module having a name matching
the specified pattern.

To be more precise...  The following code loads all the test cases defined
in package ``distutils`` except those meant to test the install
command (e.g.  the tests defined in modules ``distutils.test.test_install``
and ``distutils.test.test_install_scripts`` are not incorporated to
the resulting test suite)

::

    from dutest import PackageTestLoader
    import unittest
    import re, distutils, distutils.tests

    accepted_modules = r'distutils\.tests\.test_(?!install).*'
    loader = PackageTestLoader(pattern=re.compile(accepted_modules),
                               loader = unittest.defaultTestLoader)
    # Both statements load the same set of test cases
    suite = loader.loadTestsFromModule(distutils)
    suite = loader.loadTestsFromModule(distutils.test)

However you may want to run only the doctests defined in your own
package.  Besides you also wish to report failures by using an specific
diff algorithm (REPORT_UDIFF), your test code makes use of the with
statement and you are using Python 2.5 , and finally you want to run
the test without clearing the global namespace(s) ::

::

    from dutest import PackageTestLoader, DocTestLoader
    from __future__ import CO_FUTURE_WITH_STATEMENT
    import re, mypkg, mypkg.test
    import doctest

    accepted_modules = r'mypkg\.test\.test_(?!exclude).*'
    loader = PackageTestLoader(pattern=re.compile(accepted_modules),
                        loader = DocTestLoader(
                                optionflags = doctest.REPORT_UDIFF,
                                runopts = dict(
                                        compileflags = CO_FUTURE_WITH_STATEMENT,
                                        clear_globs = False))
                        )
    # Both statements load the same set of test cases
    suite = loader.loadTestsFromModule(mypkg)
    suite = loader.loadTestsFromModule(mypkg.test)

If loader is not specified, the default behavior is equivalent to load
all doctests and instaces of TestCase found for each each module i.e.  ::

::

    import dutest, unittest

    # Equivalent statements
    loader = dutest.PackageTestLoader(pattern)
    loader = dutest.PackageTestLoader(pattern,
                        loader = dutest.defaultTestLoader)
    loader = dutest.PackageTestLoader(pattern,
                        loader = dutest.MultiTestLoader(
                                        unittest.defaultTestLoader,
                                        dutest.DocTestLoader()))
                        )

And many more scenarios are possible if other loaders are specified.
I like this kind of code in which the most relevant behavior arises
from interactions among objects while working together, instead of the
one-class-makes-everything approach, or even some forms of inheritance.
Its like building construction...  you have the simplest building blocks...
put them together to form either a small simple house, a big hotel, a
castle, a fortress...  maybe an igloo 8-O ?  It is up to you... ;) I
am personally
designing my Taj Mahal :D

A few extra parameters offer minor options to customize the loader's
behavior.  What do you think about this?  Is it a good idea?  Is there
anything wrong with it?  Is it useful for you ?  (it is for me ;)

All this is included in ``dutest`` module (version 0.2.1 [3]_),
available for download at the `FLiOOPS project download area`_ and
`PyPI`_.


.. [1] Why should everybody have a first reference? ;)

.. [2] Gamma E., Helm R., Johnson R., Vlissides J., Design Patterns:
       Elements of Reusable Object-Oriented Software, Reading, Mass.:
       Addison-Wesley, 1995.  ISBN 0-201-63361-2.

.. [3] The minor version number has been upgraded.  In this case the
       following rules have been considered ::

    - **versions 0.1.x** : Contain code specific only to doctest /
      unittest integration.

    - **versions 0.2.x** : Contain also helper classes to
      provide useful functionality which can "enhance" (simplify) the
      code written for testing purposes.

.. _FLiOOPS project download area:
https://sourceforge.net/project/showfiles.php?group_id=220287&package_id=265911

.. _PyPI: http://pypi.python.org/pypi/dutest/0.2.1


-- 
Regards,

Olemis.



More information about the testing-in-python mailing list