doctest en Python: prueba ejemplos

Publicado el: 15/08/2026
Tempo de leitura: 5 minutos
Portátil con código que representa ejemplos ejecutables probados con doctest en Python

El módulo doctest en Python encuentra texto que parece una sesión interactiva dentro de docstrings o archivos de documentación, ejecuta cada comando y compara la salida real con la documentada. Convierte ejemplos en documentación ejecutable y ayuda a mantener tutoriales, ayuda y snippets sincronizados con el código.

Funciona mejor con ejemplos pequeños, deterministas y fáciles de leer. No sustituye una suite completa, especialmente para estados complejos, red, concurrencia, fixtures elaboradas o reglas que necesitan aserciones detalladas.

Escribe el primer ejemplo

Una docstring puede incluir prompts >>> seguidos de la salida esperada.

def doble(valor):
    """Devuelve el doble.

    >>> doble(4)
    8
    >>> doble(-3)
    -6
    """
    return valor * 2

El texto sigue las convenciones de una sesión interactiva. La salida comienza inmediatamente después del comando y termina ante otro prompt o una línea vacía.

Ejecuta con testmod

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

Al ejecutar el archivo, no ver salida significa que todos los ejemplos pasaron. Usa modo detallado para observar cada intento:

python modulo.py -v

En CI, comprueba el resultado o integra doctest con unittest para que una configuración incorrecta no parezca éxito.

Usa la línea de comandos

python -m doctest modulo.py
python -m doctest -v modulo.py

Pasar un miembro de paquete como archivo aislado puede romper imports relativos. En paquetes, suele ser mejor importarlo dentro del contexto correcto.

Prueba archivos de documentación

testfile() lee ejemplos interactivos de un archivo textual.

import doctest

resultado = doctest.testfile(
    "guia.txt",
    module_relative=False,
)
print(resultado)

El archivo se trata como una docstring grande, lo que permite verificar tutoriales sin colocar todos los ejemplos en el código.

Comprende el contexto

Cada docstring recibe normalmente una copia superficial de los globals del módulo. Ejemplos dentro de la misma docstring comparten nombres; docstrings diferentes normalmente no.

def ejemplo_estado():
    """
    >>> valores = [1, 2]
    >>> valores.append(3)
    >>> valores
    [1, 2, 3]
    """

Una copia superficial todavía comparte objetos mutables referenciados. Evita estado global real y limpia archivos, variables y conexiones.

Proporciona globals explícitos

globs y extraglobs preparan nombres.

doctest.testfile(
    "ejemplos.txt",
    globs={"Cliente": Cliente},
    extraglobs={"config": config_prueba},
    module_relative=False,
)

No inyectes credenciales de producción, sesiones reales ni recursos irreversibles. Usa fakes y directorios temporales.

Documenta excepciones

Un ejemplo puede incluir el traceback esperado. Las líneas intermedias suelen ignorarse y se compara el tipo y detalle.

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

Si el mensaje cambia entre versiones, IGNORE_EXCEPTION_DETAIL permite centrarse en el tipo. Úsalo solo cuando el texto no sea parte del contrato.

Normaliza espacios

NORMALIZE_WHITESPACE considera equivalentes las secuencias de espacios y saltos.

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

Aplica la directiva solo donde el formato sea irrelevante. Activarla globalmente puede ocultar regresiones.

Usa ELLIPSIS con cuidado

ELLIPSIS permite que ... coincida con cualquier fragmento.

>>> objeto
<MiObjeto id=...>  # doctest: +ELLIPSIS

Mantén prefijos y sufijos estables. Una elipsis demasiado amplia puede aceptar una salida equivocada.

Representa líneas vacías

Una línea vacía termina la salida esperada. Para exigir una línea en blanco, escribe <BLANKLINE>.

>>> print("primera\n\ntercera")
primera
<BLANKLINE>
tercera

Esta regla causa muchos fallos al copiar salida multilínea.

Evita orden no determinista

No compares sets o mappings cuyo orden no sea parte de la API.

>>> sorted(obtener_tags())
['api', 'python', 'prueba']

Formatea floats explícitamente. Evita timestamps, direcciones de memoria, UUID aleatorios, rutas temporales y mensajes dependientes de plataforma.

Añade ejemplos con __test__

Un mapping __test__ permite añadir casos que no aparecen en la ayuda principal.

__test__ = {
    "casos_extra": """
    >>> doble(0)
    0
    """,
}

Los valores pueden ser strings, funciones o clases y sus docstrings se examinan.

Qué objetos se buscan

testmod() examina docstring del módulo, funciones, clases, métodos y objetos de __test__. Los objetos importados desde otros módulos no se buscan automáticamente.

La guía de pydoc en Python explica la visualización de documentación. Para listar clases y funciones sin importar, consulta pyclbr en Python.

Integra con unittest

DocTestSuite() convierte ejemplos de un módulo en una suite unittest.

import doctest
import unittest
import mi_modulo


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

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

DocFileSuite() hace lo mismo para archivos de texto. Así la ejecución y los reportes quedan integrados.

Prepara y limpia recursos

Las suites aceptan setUp y tearDown.

def preparar(test):
    test.globs["repositorio"] = RepositorioTemporal()


def limpiar(test):
    test.globs["repositorio"].close()

suite = doctest.DocTestSuite(
    mi_modulo,
    setUp=preparar,
    tearDown=limpiar,
)

La limpieza debe ocurrir incluso tras fallos. Prefiere tempfile, mocks y recursos en memoria.

FAIL_FAST y reportes

La opción -f activa FAIL_FAST. Otras flags muestran diferencias unificadas, de contexto o dentro de líneas.

python -m doctest -v -f guia.txt

Fallar pronto ayuda durante depuración. En CI puede ser mejor informar todos los ejemplos rotos.

Omite casos deliberadamente

>>> abrir_navegador()  # doctest: +SKIP

SKIP sirve para ejemplos ilustrativos o servicios no disponibles. Revisa los skips porque pueden ocultar documentación rota.

Analiza ejemplos programáticamente

DocTestParser extrae objetos Example.

from doctest import DocTestParser

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

DocTestFinder, DocTestRunner y OutputChecker permiten integraciones personalizadas. Usa la API básica salvo necesidad real.

Seguridad

Doctest ejecuta los ejemplos encontrados. Nunca ejecutes documentación enviada por usuarios, paquetes desconocidos o repositorios no confiables en el proceso principal.

Usa un proceso o contenedor restringido, timeout, límites de memoria y CPU, sin credenciales de producción, con filesystem temporal y red controlada. Importar el módulo ya puede ejecutar código superior.

Tracebacks y diagnósticos

La guía de traceback en Python explica el formato de excepciones. En doctest, incluye solo detalles estables y evita rutas y líneas.

Introspección y documentación

inspect en Python ayuda a recuperar firmas y docstrings antes de construir suites. La introspección de objetos vivos suele exigir importar el código.

Cuándo no usar doctest

  • Flujos largos con fixtures complejas.
  • Salidas grandes o inestables.
  • Pruebas de concurrencia y tiempo.
  • Integraciones reales de red y base de datos.
  • Property testing con muchos valores.
  • Reglas críticas con aserciones detalladas.

Usa unittest, pytest o herramientas especializadas y deja doctest para ejemplos públicos.

Buenas prácticas

  • Mantén ejemplos cortos y deterministas.
  • Prueba comportamiento público.
  • Ordena colecciones antes de mostrarlas.
  • Formatea floats explícitamente.
  • Usa directivas localmente.
  • Evita elipsis excesivas.
  • Ejecuta documentación en CI.
  • Aísla documentación no confiable.

Conclusión

doctest en Python mantiene ejemplos sincronizados y convierte documentación en pruebas ejecutables. Es excelente para APIs pequeñas, tutoriales y regresiones legibles cuando la salida es estable.

Consulta la documentación oficial de doctest y la documentación de unittest.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Desarrollador configurando un servidor HTTPS y certificado TLS con Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    HTTPSServer: crea un servidor HTTPS local en Python

    Aprende HTTPSServer en Python para crear servicios HTTPS locales, configurar certificados, usar hilos y comprender sus límites.

    Ler mais

    Tempo de leitura: 4 minutos
    08/10/2026
    Archivos protegidos que representan extracción segura de TAR con Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    tarfile extraction_filter: extrae TAR con seguridad

    Aprende tarfile extraction_filter en Python para extraer archivos TAR con validación, seguridad y control de rutas.

    Ler mais

    Tempo de leitura: 6 minutos
    08/10/2026
    Código Python mostrando avisos controlados con catch_warnings
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    catch_warnings: captura warnings en pruebas Python

    Aprende catch_warnings en Python para capturar, probar y controlar avisos con filtros específicos y alcance seguro.

    Ler mais

    Tempo de leitura: 5 minutos
    07/10/2026
    Código Python que representa referencias persistentes de pickle
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    pickle persistent_id: serializa referencias externas

    Aprende pickle persistent_id en Python para referencias externas estables, validación, seguridad, rendimiento y compatibilidad.

    Ler mais

    Tempo de leitura: 5 minutos
    07/10/2026
    Código binario que representa buffers y vistas de memoria en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    memoryview.count: cuenta valores sin copiar buffers

    Aprende memoryview.count en Python para contar bytes y valores en buffers sin copias, con formatos, límites y buenas prácticas.

    Ler mais

    Tempo de leitura: 6 minutos
    06/10/2026
    Código Python y anotaciones de tipos
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    annotationlib: evita imports circulares en anotaciones

    Aprende annotationlib en Python para inspeccionar anotaciones diferidas, evitar imports circulares y crear herramientas seguras.

    Ler mais

    Tempo de leitura: 6 minutos
    06/10/2026