Python Doctests: The Complete Guide to Documentation-Driven Testing
Writing documentation is essential, but code examples in documentation frequently rot over time as codebases evolve. Python's built-in doctest module solves this problem by allowing you to write executable code examples directly inside your docstrings. The system verifies that the actual function output matches your documented example output.
By combining doctest (for living documentation correctness) and pytest (as your primary test runner), you get a symbiotic testing strategy that guarantees your code works and your documentation is always truthful.
This guide covers when to use doctests, how to write them, the various ways to execute them, and how to optimize your developer workflow in VS Code and Gitpod.
When and Why to Use Doctest
Doctests are not intended to replace comprehensive unit test suites. Instead, they serve as a documentation correctness tool.
The Golden Rules of Doctesting
- Use doctests for:
- Deterministic, pure functions (given input $X$, output is always $Y$).
- Reusable utility helpers (e.g., text sanitizers, email validators, unit converters).
- Algorithmic examples where demonstrating usage makes the documentation easier to read.
- Avoid doctests for:
- Side-effect-heavy routines (database integrations, network calls, file system writes).
- Functions requiring complex mocking, fixtures, or environment setup.
- Verifying edge conditions or exception hierarchies (use Pytest for these).
In a typical production application, roughly 10% to 20% of your helper functions are suitable for doctests. The rest should reside in traditional test files.
Writing Your First Doctest
To write a doctest, format your docstring examples to mimic an interactive Python shell session using the >>> prefix:
def sanitize_vegetable_name(name: str) -> str:
"""
Removes trailing whitespace and capitalizes the vegetable name.
>>> sanitize_vegetable_name(" carrot ")
'Carrot'
>>> sanitize_vegetable_name("BROCCOLI")
'Broccoli'
"""
return name.strip().capitalize()
Various Ways to Run Doctests
Python and Pytest provide multiple options for executing doctests, depending on your preferred workflow.
1. From the Command Line
To run doctests in a specific file on the fly, invoke the module directly:
python -m doctest -v your_script.py
(The -v verbose flag outputs exactly which examples ran and their statuses).
2. Embedding in the Script Block
You can instruct Python to execute doctests programmatically when running the script directly:
if __name__ == "__main__":
import doctest
doctest.testmod(verbose=True)
3. Testing Separate Text Files
If you write user guides or READMEs in separate .txt or .rst files, you can validate those code blocks directly:
import doctest
doctest.testfile("README.txt", verbose=True)
4. Running specific objects
If you only want to validate the docstrings of a specific function or class:
import doctest
doctest.run_docstring_examples(sanitize_vegetable_name, globals(), verbose=True)
5. Running with Pytest (Recommended)
Pytest natively supports collecting and running doctests. Simply run:
pytest --doctest-modules your_script.py
Symbiotic Testing: Pytest + Doctest Integration
Instead of running two separate test suites, configure Pytest to run your unit tests and doctests together.
Configuration in pyproject.toml
Add the --doctest-modules flag to your default Pytest options so it scans all docstrings automatically:
[tool.pytest.ini_options]
addopts = "--doctest-modules"
Pre-commit Validation Hook
Add a Git pre-commit hook to verify both unit tests and documentation examples pass locally before code is pushed to your remote repository:
- repo: https://github.com/pre-commit/mirrors-pytest
rev: v7.4.2
hooks:
- id: pytest
IDE Setup in VS Code and Gitpod
If you are developing inside Gitpod or VS Code, you can streamline writing doctests:
- Auto-Formatting Docstrings: Use the autoDocstring extension in VS Code. It provides customized templates for docstrings, so you do not have to type the
>>>syntax manually. - Syntax Highlighting: Install a docstring syntax highlighter to color-code code examples within Python docstrings, distinguishing them from standard commentary.
- Save Verification: Always save your changes before running tests from the terminal, as external CLI runners only inspect files committed to disk.
Sources
- [1] Python Documentation: doctest Standard Library
- [2] Pytest Documentation: How to run doctests
- [3] VS Code Documentation: Python Testing in Visual Studio Code
- [4] Python Documentation: timeit module
- [5] Python Documentation: tracemalloc module
