Python doctest: Test Examples

Published on: August 15, 2026
Reading time: 5 minutes
Laptop with code representing executable examples tested with Python doctest

Python doctest finds text that resembles interactive Python sessions inside docstrings or documentation files, executes each command, and compares actual output with the documented output. It turns examples into executable documentation and helps keep tutorials, help text, and API snippets synchronized with the code.

The module works best for small, deterministic, readable examples. It is not a replacement for a complete test suite, especially for complex state, networking, concurrency, elaborate fixtures, or behavior that requires detailed assertions.

Write the first doctest

A docstring may include >>> prompts followed by expected output.

def double(value):
    """Return twice the input.

    >>> double(4)
    8
    >>> double(-3)
    -6
    """
    return value * 2

The text follows interactive-session conventions. Expected output starts immediately after the command and ends at another prompt or a blank line.

Run examples with testmod

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

Running the file produces no output when every example passes. Use verbose mode to see each attempted example:

python module.py -v

In automated builds, check the exit behavior or integrate doctests with unittest so configuration mistakes do not look like successful runs.

Use the command line

python -m doctest module.py
python -m doctest -v module.py

Passing a package member as a standalone file may break relative imports. For package code, importing it through the proper package context is often more reliable.

Test documentation files

testfile() reads interactive examples from a text file such as reStructuredText or Markdown.

import doctest

result = doctest.testfile(
    "guide.txt",
    module_relative=False,
)
print(result)

The entire file is treated like one large docstring, allowing tutorial examples to be verified without placing all of them in application source.

Understand execution context

Each discovered docstring normally receives a shallow copy of the module globals. Examples in the same docstring share names; examples from different docstrings normally do not.

def state_example():
    """
    >>> values = [1, 2]
    >>> values.append(3)
    >>> values
    [1, 2, 3]
    """

A shallow copy still shares referenced mutable objects. Avoid real global state and clean up files, environment variables, and connections after tests.

Provide explicit globals

globs and extraglobs prepare names for examples.

doctest.testfile(
    "examples.txt",
    globs={"Client": Client},
    extraglobs={"config": test_config},
    module_relative=False,
)

Do not inject production credentials, live database sessions, or irreversible resources. Use fakes, temporary directories, and test configurations.

Document exceptions

An example may include the expected traceback. Intermediate stack lines are normally ignored, while the exception type and detail are compared.

def divide(a, b):
    """
    >>> divide(10, 0)
    Traceback (most recent call last):
    ...
    ZeroDivisionError: division by zero
    """
    return a / b

If messages vary across versions, IGNORE_EXCEPTION_DETAIL can focus on the exception type. Use it only when the message is not part of the public contract.

Normalize whitespace

NORMALIZE_WHITESPACE treats whitespace sequences as equivalent.

>>> print(list(range(10)))  # doctest: +NORMALIZE_WHITESPACE
[0, 1, 2, 3, 4,
 5, 6, 7, 8, 9]

Apply the directive only where wrapping is irrelevant. Global normalization can hide meaningful formatting regressions.

Use ELLIPSIS carefully

ELLIPSIS allows ... to match arbitrary output.

>>> object_value
<MyObject id=...>  # doctest: +ELLIPSIS

Keep stable prefixes and suffixes around the marker. Broad ellipses can accept incorrect output just as a greedy regular expression can.

Represent blank lines

A blank line ends expected output. To require an actual blank line, write <BLANKLINE>.

>>> print("first\n\nthird")
first
<BLANKLINE>
third

This rule is a common source of failures in copied multiline output.

Avoid nondeterministic ordering

Do not compare sets or mappings whose display order is not part of the API.

>>> sorted(get_tags())
['api', 'python', 'test']

Format floating-point values explicitly. Avoid timestamps, memory addresses, random UUIDs, temporary paths, and platform-dependent messages unless normalized.

Add hidden examples with __test__

A module-level __test__ mapping adds doctests that do not need to appear in the main help text.

__test__ = {
    "extra_cases": """
    >>> double(0)
    0
    """,
}

Values may be strings, functions, or classes. Their docstrings are searched recursively.

Which objects are searched?

testmod() examines the module docstring, functions, classes, methods, nested class members, and objects exposed through __test__. Objects imported from other modules are not searched automatically.

The Python pydoc guide explains how documentation is displayed. To list classes and functions without importing a module, see Python pyclbr.

Integrate with unittest

DocTestSuite() turns a module’s examples into a unittest suite.

import doctest
import unittest
import my_module


def load_tests(loader, tests, pattern):
    tests.addTests(doctest.DocTestSuite(my_module))
    return tests

if __name__ == "__main__":
    unittest.main()

DocFileSuite() performs the same conversion for text files. This makes discovery, reporting, and execution consistent with normal unit tests.

Set up and clean up resources

The suite APIs accept setUp and tearDown callbacks.

def set_up(test):
    test.globs["repository"] = TemporaryRepository()


def tear_down(test):
    test.globs["repository"].close()

suite = doctest.DocTestSuite(
    my_module,
    setUp=set_up,
    tearDown=tear_down,
)

Cleanup must occur even after failures. Prefer tempfile, mocks, and in-memory resources.

Fail fast and improve reports

The command-line -f option enables FAIL_FAST. Other flags show unified, context, or intraline differences.

python -m doctest -v -f guide.txt

Fail-fast is convenient while debugging. A full CI run may be more valuable because it reports all stale examples at once.

Skip examples deliberately

>>> open_browser()  # doctest: +SKIP

SKIP is appropriate for purely illustrative commands or unavailable services. Review skips regularly because they can hide broken documentation.

Parse examples programmatically

DocTestParser extracts Example objects from text.

from doctest import DocTestParser

text = """
>>> 2 + 2
4
"""
examples = DocTestParser().get_examples(text)
print(examples[0].source, examples[0].want)

DocTestFinder, DocTestRunner, and OutputChecker enable custom integrations. Use the basic API unless you need specialized discovery or comparison rules.

Security

Doctest executes the examples it discovers. Never run user-submitted documentation, unknown packages, or untrusted repositories in the main application process.

Use a restricted process or container with a timeout, memory and CPU limits, no production credentials, a temporary filesystem, and network restrictions. Importing the tested module can itself execute top-level code before examples run.

Tracebacks and diagnostics

The Python traceback guide explains exception formatting. In doctests, include only stable exception details and omit file paths and line numbers unless they add instructional value.

Introspection and documentation

Python inspect can help documentation tools retrieve signatures and docstrings before building suites. Remember that live-object introspection normally requires importing the target code.

When doctest is not the right tool

  • Long workflows with complex fixtures.
  • Large or unstable output.
  • Concurrency and timing tests.
  • Real network and database integration.
  • Property testing across many values.
  • Critical rules that need detailed assertions.

Use unittest, pytest, or specialized frameworks for these cases and keep doctests focused on public examples.

  • Keep examples short and deterministic.
  • Test public behavior instead of internals.
  • Sort collections before displaying them.
  • Format floating-point output explicitly.
  • Use directives locally.
  • Avoid excessive ellipsis matching.
  • Run documentation tests in CI.
  • Isolate untrusted documentation.

Conclusion

Python doctest keeps examples synchronized with implementation and turns documentation into executable tests. It is excellent for small APIs, tutorials, and readable regressions when outputs are stable.

Consult the official doctest documentation and the Python unittest documentation.

Share:

Facebook
WhatsApp
Twitter
LinkedIn

Article content

    Related articles

    Source code on screen representing class and function browsing with Python pyclbr
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python pyclbr: Inspect Modules Safely

    Learn Python pyclbr to list classes, functions, methods, and nested definitions without importing or executing the target module.

    Ler mais

    Tempo de leitura: 5 minutos
    15/08/2026
    Monitor with binary code representing Python bytecode opcode instructions
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python opcode: Explore Bytecode

    Learn Python opcode to map bytecode instructions, arguments, jumps, caches, and stack effects through the documented dis APIs.

    Ler mais

    Tempo de leitura: 5 minutos
    15/08/2026
    Developer investigating memory usage with Python tracemalloc
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python tracemalloc: Find Memory Leaks

    Use Python tracemalloc to compare snapshots, locate memory growth, and investigate leaks in long-running applications.

    Ler mais

    Tempo de leitura: 5 minutos
    15/08/2026
    Code with type annotations representing introspection with Python annotationlib
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python annotationlib: Read Annotations

    Learn Python annotationlib in 3.14 to retrieve annotations as values, ForwardRef proxies, or strings while controlling execution risks.

    Ler mais

    Tempo de leitura: 5 minutos
    14/08/2026
    Organized archive binders representing modules imported directly from ZIP files with Python zipimport
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python zipimport: Import from ZIP Files

    Learn Python zipimport to load modules and packages from ZIP archives, work with importers, and protect plugin systems.

    Ler mais

    Tempo de leitura: 5 minutos
    14/08/2026
    Directory diagram representing site-packages paths and Python site module configuration
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python site: Understand Package Paths

    Learn the Python site module to understand site-packages, user site, .pth files, sitecustomize, usercustomize, virtual environments, and startup flags.

    Ler mais

    Tempo de leitura: 6 minutos
    14/08/2026