Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python test discovery with doctests, coverage and parallelism

... and a pony! No, seriously. I am looking for a way to organize tests that "just works". Most things do work, but not all pieces fit together. So here is what I want:

  • Having tests automatically discovered. This includes doctests. Note that the sum of doctests must not appear as a single test. (i.e. not what py.test --doctest-modules does)
  • Being able to run tests in parallel. (Something like py.test -n from xdist)
  • Generating a coverage report.
  • Make python setup.py test just work.

My current approach involves a tests directory and the load_tests protocol. All files contained are named like test_*.py. This makes python -m unittest discover just work, if I create a file test_doctests.py with the following content.

import doctest
import mymodule1, mymodule2
def load_tests(loader, tests, ignore):
    tests.addTests(doctest.DocTestSuite(mymodule1))
    tests.addTests(doctest.DocTestSuite(mymodule2))
    return tests

This approach also has the upside that one can use setuptools and supply setup(test_suite="unittest2.collector").

However this approach has a few problems.

  • coverage.py expects to run a script. So I cannot use unittest2 discovery here.
  • py.test does not run load_tests functions, so it does not find the doctests and the --doctest-modules option is crap.
  • nosetests runs the load_tests functions, but does not supply any parameters. This appears totally broken on the side of nose.

How can I make things work better than this or fix some of the issues above?

like image 655
Helmut Grohne Avatar asked Jun 07 '13 11:06

Helmut Grohne


People also ask

Can doctest be used to test Docstrings?

There are several common ways to use doctest: To check that a module's docstrings are up-to-date by verifying that all interactive examples still work as documented. To perform regression testing by verifying that interactive examples from a test file or a test object work as expected.

How do I run all Python Doctests?

Right click on a blank space in the python code, and there is a menu option to run all the Doctests found in the file, not just the tests for one function.

What is the correct way to run all Doctests in a given file from the command-line?

To run the tests, use doctest as the main program via the -m option to the interpreter. Usually no output is produced while the tests are running, so the example below includes the -v option to make the output more verbose.


1 Answers

This is an old question, but the problem still persists for some of us! I was just working through it and found a solution similar to kaapstorm's, but with much nicer output. I use py.test to run it, but I think it should be compatible across test runners:

import doctest
from mypackage import mymodule

def test_doctest():
    results = doctest.testmod(mymodule)
    if results.failed:
        raise Exception(results)

What I end up with in a failure case is the printed stdout output that you would get from running doctest manually, with an additional exception that looks like this:

Exception: TestResults(failed=1, attempted=21)

As kaapstrom mentioned, it doesn't count tests properly (unless there are failures) but I find that isn't worth a whole lot provided the coverage numbers come back high :)

like image 149
ajk8 Avatar answered Oct 06 '22 14:10

ajk8