Recipe8.10.Using doctest with unittest in Python 2.4


Recipe 8.10. Using doctest with unittest in Python 2.4

Credit: John Nielsen

Problem

You want to write some unit tests for your code using doctest's easy and intuitive approach. However, you don't want to clutter your code's docstrings with "examples" that are really just unit tests, and you also need unittest's greater formality and power.

Solution

Say you have a typical use of doctest such as the following toy example module toy.py:

def add(a, b):     """ Add two arbitrary objects and return their sum.     >>> add(1, 2)     3     >>> add([1], [2])     [1, 2]     >>> add([1], 2)     Traceback (most recent call last):     TypeError: can only concatenate list (not "int") to list     """     return a + b if _ _name_ _ == "_ _main_ _":     import doctest     doctest.testmod( )

Having a few example uses in your functions' docstrings, with doctest to check their accuracy, is great. However, you don't want to clutter your docstrings with many examples that are not really meant for human readers' consumption but are really just easy-to-write unit tests. With Python 2.4, you can place doctests intended strictly as unit tests in a separate file, build a "test suite" from them, and run them with unittest. For example, place in file test_toy.txt the following lines (no quoting needed):

>>> import toy >>> toy.add('a', 'b') 'ab' >>> toy.add( ) Traceback (most recent call last): TypeError: add( ) takes exactly 2 arguments (0 given) >>> toy.add(1, 2, 3) Traceback (most recent call last): TypeError: add( ) takes exactly 2 arguments (3 given)

and add at the end of toy.py a few more lines:

    import unittest     suite = doctest.DocFileSuite('test_toy.txt')     unittest.TextTestRunner( ).run(suite)

Now, running python toy.py at a shell command prompt produces the following output:

. ---------------------------------------------------------------------- Ran 1 test in 0.003s OK

Discussion

The doctest module of the Python Standard Library is a simple, highly productive way to produce a plain but useful bunch of unit tests for your code. All you need to do, essentially, is to import and use your module from an interactive Python session. Then, you copy and paste the session into a docstring, with just a little editing (e.g. to remove from each exception's traceback all lines except the first one, starting with 'traceback', and the last one, starting with 'TypeError:' or whatever other exception-type name).

Docstrings

Documentation strings (docstrings) are an important feature that Python offers to help you document your code. Any module, class, function or method can have a string literal as its very first "statement". If so, then Python considers that string to be the docstring for the module, class, function, or method in question and saves it as the _ _doc_ _ attribute of the respective object. Modules, classes, functions, and methods that lack docstrings have None as the value of their _ _doc_ _ attribute.

In Python's interactive interpreter, you can examine the "docstring" of an object, as well as other helpful information about the object, with the command help(theobject). Module pydoc, in the Python Standard Library, uses docstrings, as well as introspection, to generate and optionally serve web pages of information about modules, classes, functions, and methods. (See http://pydoc.org/ for a web site containing pydoc-generated documentation about the Python Standard Library as well as the standard Python online documentation.)


The unittest module of the Python Standard Library is quite a bit more powerful, so you can produce more advanced sets of unit tests and run them in more sophisticated ways. Writing the unit tests is not quite as simple and fast as with doctest.

Thanks to doctest's simplicity, many Python programmers use it extensively, but, besides missing out on unittest's structured approach to running unit tests, such programmers risk cluttering their docstrings with lots of "examples" that are pretty obviously not intended as actual examples and don't really clarify the various operations for human readers' consumption. Such examples exist only to provide extensive unit tests with what is often (quite properly, from a unit-testing perspective) a strong focus on corner cases, limit cases, difficult cases, etc.

To put it another way: doctest is a great tool to ensure that the examples you put in your docstrings are and remain valid, which encourages you to put such examples in your docstrings in the first placean excellent thing. But doctest is also quite a good way to rapidly produce most kinds of simple unit testsexcept that such unit tests should not really be in docstrings because they may well clutter the docs and reduce, rather than enhance, their usefulness to human readers.

Python 2.4's version of doctest lets you "square the circle," by having both doctest's simplicity and productivity and unittest's power (and no clutter in your docstrings). Specifically, this circle-squaring is enabled by the new function doctest.DocFileSuite. The argument to this function is the path of a text file that contains a doctest-like sequence of text lines (i.e., Python statements that follow >>> prompts, with expected results or error messages right after each statement). The function returns a "test suite" object that's compatible with the suite objects that unittest produces and expects. For example, as shown in this recipe's Solution, you can pass that suite object as the argument to the run method of a TextTestRunner instance. Note that the text file you pass to doctest.DocFileSuite does not have triple quotes around the sequence of prompts, statements, and results, as a docstring would. Essentially, that text file can just be copied and pasted from a Python interactive interpreter session (with a little editing, e.g., of exceptions' tracebacks, as previously mentioned).

See Also

Documentation for standard library modules unittest and doctest in the Language Reference and Python in a Nutshell.



Python Cookbook
Python Cookbook
ISBN: 0596007973
EAN: 2147483647
Year: 2004
Pages: 420

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net