# Automatically run doctest every time program is run

I would like this to happen every time I run a program from the command line. Is my approach Pythonic? I'm interested to know whether there is any problem with readability or correctness. Any general advice on better ways of doing things or potential problems are also welcome.

Although the main function is just an example, I'm looking for a review of the rest of the code, which I intend to append to all my existing programs and is therefore not just example code. I have included the example main function here as I used this to observe the different behaviour when including a passing or failing doctest. If any doctest fails, this will be printed to stdout and the program will not run. If all doctests pass, there is no output from the testing and the program runs as normal.

"""Auto doctest.

Code to run the doctests before the main code every time the code is run
from the command line. Uses assert so that running the code in optimised
mode will skip the testing.
"""

def main(arguments):
"""Perform the functions of the program.

Example doctest:

>>> 1 + 1
2

"""
print('The main function received the following arguments:')
print(arguments)

def _doctests_pass():
"""Return True if all doctests pass, otherwise False."""
import doctest
failure_count, test_count = doctest.testmod()
return failure_count == 0

if __name__ == '__main__':
assert _doctests_pass()
import sys
main(sys.argv)

-

Make it a habit to run pyflakes and the pep8 tools on Python projects. pep8 finds some style violations in this code:

• There should be two blank lines before global method declarations (main and _doctests_pass in your case)
• There shouldn't be trailing whitespace at the end of line 3 and 4.

You can install pyflakes and pep8 using pip. See also the PEP8 documentation for more details on Python style.

By the way, I think running unit tests is a job for a Continuous Integration system, not something to do every time you run the code. The point of testing is to run after every code change. You're going way further, but it's completely pointless. If the code hasn't changed, then the repeated tests are just wasting CPU cycles. I think it would be better to abandon this approach and leave this up to a Continuous Integration tool, where you could include other goodies easily like pep8, pyflakes, and others.

If this is not a team project, then setting up a Continuous Integration system could be overkill. A good middle ground can be setting up a pre-commit hook with your version control system. That should be relatively easy to do, and ensure that all your committed code pass your tests.

-
Thanks for this. I will avoid trailing whitespace from now on. I did actually have two blank lines between the global functions but it seemed a shame to have a scroll bar for just two lines so I took them down to just one blank line when I pasted the code into the question. I should have mentioned this (or not done it...). Now that you've brought these to my attention I might try and include pyflakes and pep8 automatically on running too, to pick me up on it in future... – trichoplax Apr 14 '14 at 19:40
I see your point - my approach doesn't make sense for a team. This is something I mainly intended for code I use myself, written alone. Since there isn't an integration step I want the tests to just look after themselves and alert me when they are not happy, rather than me having to ask them if they are happy. However, if the tests take longer than a second then running them when there are no changes to the code is going to get annoying. To avoid limiting the tests I might try to trigger the doctests only if the code has changed since last tested. I'll also read up on Continuous Integration... – trichoplax Apr 14 '14 at 20:55
That last paragraph sounds like exactly what I want. I must admit my attempt to check the time last tested is getting a little unwieldy so I'll read up on pre-commit hooks rather than reinvent the wheel. Unfortunately I can't give you another upvote since it's part of the same answer... Thanks very much for your help. – trichoplax Apr 14 '14 at 22:32
@githubphagocyte No worries, I can! :) There are other options if commit hooks are too late: make, grunt, and Infinitest for Eclipse (if it supports Python). Definitely don't punish use when you can test only when the code changes--even when it's just you (unless you're a masochist in which case a few well-placed calls to sys.sleep are in order). – David Harkness Apr 15 '14 at 1:46