Python > Testing in Python > Doctests > Writing Tests in Docstrings

Doctests: Testing within Docstrings

This example demonstrates how to write and run doctests within your Python docstrings. Doctests are a simple way to embed test cases directly into your code's documentation, making it easier to keep your code and tests synchronized. Doctests are designed to find Python code examples and execute them, then verify that the output matches the expected result that is written in the doctest.

Basic Doctest Example

This code defines a function `add` and includes doctests within its docstring. The lines starting with `>>>` are the code to be executed, and the following line is the expected output. When `doctest.testmod()` is run, it will execute these tests and report any failures. The `if __name__ == '__main__':` block ensures that the tests are only run when the script is executed directly, not when it's imported as a module.

def add(a, b):
    """Return the sum of a and b.

    >>> add(2, 3)
    5
    >>> add(-1, 1)
    0
    >>> add(0, 0)
    0
    """
    return a + b

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

How to Run Doctests

To run the doctests, save the code to a Python file (e.g., `my_module.py`) and then execute it from the command line: `python my_module.py -v`. The `-v` flag enables verbose output, which shows you the details of each test that is run.

Concepts Behind Doctests

Doctests work by parsing the docstrings of functions, classes, and modules. They look for interactive Python sessions (lines starting with `>>>`) and compare the output of those sessions to the expected output provided in the docstring. If the output doesn't match, the doctest fails.

Real-Life Use Case

Doctests are excellent for documenting simple functions and demonstrating how to use them. For example, you could use doctests to show how to use a utility function that converts temperatures from Celsius to Fahrenheit. They are also helpful for verifying the behavior of small code snippets in documentation.

Best Practices

  • Keep doctests concise and focused.
  • Use them primarily for simple examples and unit tests.
  • Ensure your docstrings accurately reflect the current behavior of your code.
  • Update the doctests whenever you change the code's functionality.

Interview Tip

Being familiar with doctests shows that you care about both code quality and documentation. You can mention that doctests are a quick and easy way to add basic testing to your code, particularly when demonstrating how to use a function or class.

When to Use Them

Use doctests for documenting simple functions and providing basic examples. They are also a good choice when you want to quickly verify that your code is working as expected, without setting up a separate testing framework. Avoid doctests for complex logic or when you need more sophisticated testing features (e.g., mocking, test fixtures).

Memory Footprint

Doctests generally have a minimal memory footprint, as they are executed only when `doctest.testmod()` is called. The memory usage is primarily determined by the code being tested within the doctests themselves.

Alternatives

Alternatives to doctests include `unittest`, `pytest`, and `nose`. These frameworks offer more advanced features, such as test discovery, fixtures, and mocking. However, they also require more setup and configuration.

Pros

  • Easy to write and integrate into existing code.
  • Keeps tests and documentation together.
  • Great for simple examples and unit tests.

Cons

  • Not suitable for complex testing scenarios.
  • Can be difficult to maintain if docstrings become too long or complicated.
  • Limited features compared to dedicated testing frameworks.

Doctest with Exception Handling

This code demonstrates how to test for exceptions using doctests. The expected output includes the traceback and the specific exception that should be raised. Note the `Traceback` and the specific `ZeroDivisionError` in the docstring.

def divide(a, b):
    """Divide a by b.

    >>> divide(10, 2)
    5.0

    >>> divide(5, 0)
    Traceback (most recent call last):
    ZeroDivisionError: division by zero
    """
    if b == 0:
        raise ZeroDivisionError("division by zero")
    return a / b

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

FAQ

  • How do I ignore certain parts of the output in a doctest?

    You can use the `doctest.ELLIPSIS` option to ignore variable parts of the output. For example, if you have a dictionary with unpredictable order, you can use `...` to match any content.
  • Can I use doctests to test classes and methods?

    Yes, you can embed doctests within the docstrings of classes and methods, just like you do with functions.
  • How do I handle floating-point precision in doctests?

    Use `round()` to round the result to a specific number of decimal places, or use the `doctest.Approx` helper, which allows comparisons with a certain tolerance.