Python > Quality and Best Practices > Testing > Doctests

Doctests for Function Verification

This example demonstrates how to use doctests to verify the correctness of a Python function. Doctests embed test cases directly within the function's docstring, making them easily accessible and maintainable.

Basic Doctest Example

This code defines a simple `add` function and includes doctests within its docstring. The `>>>` symbol indicates an interactive Python interpreter session. The lines following `>>>` are the function calls, and the lines below them are the expected outputs. The `doctest.testmod()` function automatically discovers and runs the doctests within the current 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()

Running Doctests

To run the doctests, save the code to a Python file (e.g., `my_module.py`) and execute it from the command line: `python my_module.py`. If all tests pass, there will be no output. If any tests fail, the `doctest` module will print detailed information about the failures, including the expected output and the actual output.

Concepts Behind Doctests

Doctests leverage the interactive nature of the Python interpreter. They parse the docstrings, identify lines starting with `>>>`, treat them as Python code, execute the code, and compare the actual output with the expected output. This approach tightly integrates documentation and testing.

Real-Life Use Case

Imagine you are developing a complex function for financial calculations. Using doctests, you can embed examples directly within the function's documentation, illustrating how to use the function and verifying its correctness. For example, you could demonstrate how to calculate compound interest with different inputs and expected outcomes.

Best Practices

  • Keep doctests concise and focused.
  • Use doctests to illustrate common use cases and edge cases.
  • Ensure the expected output is accurate and reflects the intended behavior of the code.
  • Update doctests whenever the code changes.
  • Combine doctests with other testing frameworks like `unittest` for comprehensive testing.

Interview Tip

When discussing testing methodologies in a Python interview, mentioning doctests demonstrates an understanding of built-in testing capabilities and the importance of integrating documentation with testing. You can highlight their simplicity and ease of use for verifying small functions and code snippets.

When to Use Doctests

Use doctests for:

  • Simple functions and methods.
  • Documenting code behavior with examples.
  • Rapidly prototyping and verifying small code snippets.
  • Illustrating the expected output for specific inputs.

Memory Footprint

Doctests generally have a minimal memory footprint, as they only run when explicitly invoked. The memory usage is primarily determined by the code being tested.

Alternatives

Alternatives to doctests include:

  • `unittest`: A more comprehensive testing framework for larger projects.
  • `pytest`: A popular third-party testing framework with a rich set of features.
  • `nose`: Another third-party testing framework (less actively maintained).

Pros

  • Simple and easy to use.
  • Tightly integrated with documentation.
  • No external dependencies required.
  • Examples serve as executable tests.

Cons

  • Not suitable for complex testing scenarios.
  • Can be difficult to maintain for large functions with many doctests.
  • Limited reporting capabilities compared to dedicated testing frameworks.
  • Output comparison can be brittle and sensitive to whitespace.

FAQ

  • How do I handle exceptions in doctests?

    You can use the `doctest.IGNORE_EXCEPTION_DETAIL` option or `doctest.ELLIPSIS` to handle exceptions and non-deterministic output in doctests. For example: `>>> 1 / 0 # doctest: +IGNORE_EXCEPTION_DETAIL`
  • How do I test functions that have side effects (e.g., printing to the console)?

    You can use the `print` statement in your doctests to check the output written to the console. You can also use `unittest.mock` to mock external dependencies or side effects for more controlled testing.