doctest

doctest

Useful module for writing docstrings and verifying these docstrings at the same time. I've primarily used it to do smaller and less complex sanity checks, e.g., ensure the type returned by a method is the expected one and such.

As you typically will provide examples of correct and incorrect usage of a method, another great benefit is that people reading through your code will find it easier to understand.

Example

example.py
"""
This is the "example" module.

The example module supplies one function, factorial().  For example,

>>> factorial(5)
120
"""

def factorial(n):
    """Return the factorial of n, an exact integer >= 0.

    >>> [factorial(n) for n in range(6)]
    [1, 1, 2, 6, 24, 120]
    >>> factorial(30)
    265252859812191058636308480000000
    >>> factorial(-1)
    Traceback (most recent call last):
        ...
    ValueError: n must be >= 0

    Factorials of floats are OK, but the float must be an exact integer:
    >>> factorial(30.1)
    Traceback (most recent call last):
        ...
    ValueError: n must be exact integer
    >>> factorial(30.0)
    265252859812191058636308480000000

    It must also not be ridiculously large:
    >>> factorial(1e100)
    Traceback (most recent call last):
        ...
    OverflowError: n too large
    """

    import math
    if not n >= 0:
        raise ValueError("n must be >= 0")
    if math.floor(n) != n:
        raise ValueError("n must be exact integer")
    if n+1 == n:  # catch a value like 1e300
        raise OverflowError("n too large")
    result = 1
    factor = 2
    while factor <= n:
        result *= factor
        factor += 1
    return result


if __name__ == "__main__":
    import doctest
    doctest.testmod()

Run python example.py to only get output if a test fails.

Run python example.py -v to get a verbose and detailed output.

Tests across multiple files

As a project grows, more than just one main file is needed. One way to manage tests across multiple files/modules, without the need for imports left right and center is to have a tests.py at the / of the project with something like below:

tests.py
import doctest
from a import b
from x import y
# ...

doctest.testmod(b)
doctest.testmod(y)

Obviously, this still requires you maintain the imports as well as adding doctest.testmod()s accordingly, but that way one can just do python tests.py -v when testing must be done and else just ignore it.

Another approach I am yet to try out is to use the method described here https://docs.python.org/3/library/doctest.html#unittest-api.

Reference

Full documentation can be found at https://docs.python.org/3/library/doctest.html

Last updated