doctest
– Prueba ejemplos interactivos de Python¶
Código fuente: Lib/doctest.py
El módulo doctest
busca pedazos de texto que lucen como sesiones interactivas de Python, y entonces ejecuta esas sesiones para verificar que funcionen exactamente como son mostradas. Hay varias maneras de usar doctest:
Para revisar que los docstrings de un módulo están al día al verificar que todos los ejemplos interactivos todavía trabajan como está documentado.
Para realizar pruebas de regresión al verificar que los ejemplos interactivos de un archivo de pruebas o un objeto de pruebas trabaje como sea esperado.
Para escribir documentación de tutorial para un paquete, generosamente ilustrado con ejemplos de entrada-salida. Dependiendo si los ejemplos o el texto expositivo son enfatizados, tiene el sabor de «pruebas literarias» o «documentación ejecutable».
Aquí hay un módulo de ejemplo completo pero pequeño:
"""
This is the "example" module.
The example module supplies one function, factorial(). For example,
>>> factorial(5)
120
"""
def factorial(n):
"""Return the factorial of n, an exact integer >= 0.
>>> [factorial(n) for n in range(6)]
[1, 1, 2, 6, 24, 120]
>>> factorial(30)
265252859812191058636308480000000
>>> factorial(-1)
Traceback (most recent call last):
...
ValueError: n must be >= 0
Factorials of floats are OK, but the float must be an exact integer:
>>> factorial(30.1)
Traceback (most recent call last):
...
ValueError: n must be exact integer
>>> factorial(30.0)
265252859812191058636308480000000
It must also not be ridiculously large:
>>> factorial(1e100)
Traceback (most recent call last):
...
OverflowError: n too large
"""
import math
if not n >= 0:
raise ValueError("n must be >= 0")
if math.floor(n) != n:
raise ValueError("n must be exact integer")
if n+1 == n: # catch a value like 1e300
raise OverflowError("n too large")
result = 1
factor = 2
while factor <= n:
result *= factor
factor += 1
return result
if __name__ == "__main__":
import doctest
doctest.testmod()
Si tu ejecutas example.py
directamente desde la línea de comandos, doctest
hará su magia:
$ python example.py
$
¡No hay salida! Eso es normal, y significa que todos los ejemplos funcionaron. Pasa -v
al script, y doctest
imprime un registro detallado de lo que está intentando, e imprime un resumen al final:
$ python example.py -v
Trying:
factorial(5)
Expecting:
120
ok
Trying:
[factorial(n) for n in range(6)]
Expecting:
[1, 1, 2, 6, 24, 120]
ok
Y demás, eventualmente terminando con:
Trying:
factorial(1e100)
Expecting:
Traceback (most recent call last):
...
OverflowError: n too large
ok
2 items passed all tests:
1 tests in __main__
8 tests in __main__.factorial
9 tests in 2 items.
9 passed and 0 failed.
Test passed.
$
¡Eso es todo lo que necesitas saber para empezar a hacer uso productivo de doctest
! Lánzate. Las siguientes secciones proporcionan detalles completos. Note que hay muchos ejemplos de doctests en el conjunto de pruebas estándar de Python y bibliotecas. Especialmente ejemplos útiles se pueden encontrar en el archivo de pruebas estándar Lib/test/test_doctest.py
.
Uso simple: verificar ejemplos en docstrings¶
La forma más simple para empezar a usar doctest (pero no necesariamente la forma que continuarás usándolo) es terminar cada módulo M
con:
if __name__ == "__main__":
import doctest
doctest.testmod()
doctest
entonces examina docstrings en el módulo M
.
Ejecutar el módulo como un script causa que los ejemplos en los docstrings se ejecuten y verifiquen:
python M.py
No mostrará nada a menos que un ejemplo falle, en cuyo caso el ejemplo fallido o ejemplos fallidos y sus causas de la falla son imprimidas a stdout, y la línea final de salida es ***Test Failed*** N failures.
, donde N es el número de ejemplos que fallaron.
Ejecútalo con el modificador -v
en su lugar:
python M.py -v
y un reporte detallado de todos los ejemplos intentados es impreso a la salida estándar, junto con resúmenes clasificados al final.
Puedes forzar el modo verboso al pasar verbose=True
a testmod()
, o prohibirlo al pasarlo verbose=False
. En cualquiera de estas casos, sys.argv
no es examinado por testmod()
(por lo que pasar o no -v
, no tiene efecto).
También hay un atajo de línea de comandos para ejecutar testmod()
. Puedes instruir al intérprete de Python para ejecutar el módulo doctest directamente de la biblioteca estándar y pasar los nombres del módulo en la línea de comandos:
python -m doctest -v example.py
Esto importará example.py
como un módulo independiente y ejecutará a testmod()
. Note que esto puede no funcionar correctamente si el archivo es parte de un paquete e importa otros submódulos de ese paquete.
Para más información de testmod()
, véase la sección API básica.
Uso Simple: Verificar ejemplos en un Archivo de Texto¶
Otra simple aplicación de doctest es probar ejemplos interactivos en un archivo de texto. Esto puede ser hecho con la función testfile()
:
import doctest
doctest.testfile("example.txt")
Este script corto ejecuta y verifica cualquier ejemplo interactivo de Python contenido en el archivo example.txt
. El contenido del archivo es tratado como si fuese un solo gran docstring; ¡el archivo no necesita contener un programa de Python! Por ejemplo, tal vez example.txt
contenga esto:
The ``example`` module
======================
Using ``factorial``
-------------------
This is an example text file in reStructuredText format. First import
``factorial`` from the ``example`` module:
>>> from example import factorial
Now use it:
>>> factorial(6)
120
Ejecutar doctest.testfile("example.txt")
entonces encuentra el error en esta documentación:
File "./example.txt", line 14, in example.txt
Failed example:
factorial(6)
Expected:
120
Got:
720
Como con testmod()
, testfile()
no mostrará nada a menos que un ejemplo falle. Si un ejemplo no falla, entonces los ejemplos fallidos y sus causas son impresas a stdout, usando el mismo formato como testmod()
.
Por defecto, testfile()
busca archivos en el directorio del módulo al que se llama. Véase la sección API básica para una descripción de los argumentos opcionales que pueden ser usados para decirle que busque archivos en otros lugares.
Como testmod()
, la verbosidad de testfile()
puede ser establecida con el modificador de la línea de comandos -v
o con el argumento por palabra clave opcional verbose.
También hay un atajo de línea de comandos para ejecutar testfile()
. Puedes indicar al intérprete de Python para correr el módulo doctest directamente desde la biblioteca estándar y pasar el nombre de los archivos en la línea de comandos:
python -m doctest -v example.txt
Porque el nombre del archivo no termina con .py
, doctest
infiere que se debe ejecutar con testfile()
, no testmod()
.
Para más información en testfile()
, véase la sección API básica.
Cómo funciona¶
Esta sección examina en detalle cómo funciona doctest: qué docstrings revisa, cómo encuentra ejemplos interactivos, qué contexto de ejecución usa, cómo maneja las excepciones, y cómo las banderas pueden ser usadas para controlar su comportamiento. Esta es la información que necesitas saber para escribir ejemplos de doctest; para información sobre ejecutar doctest en estos ejemplos, véase las siguientes secciones.
¿Qué docstrings son examinados?¶
Se busca en el docstring del módulo, y todos los docstrings de las funciones, clases, y métodos. Los objetos importados en el módulo no se buscan.
Además, si M.__test__
existe y «es verdaderos», debe ser un diccionario, y cada entrada mapea un nombre (cadena de caracteres) a un objeto de función, objeto de clase, o cadena de caracteres. Se buscan los docstrings de los objetos de función o de clase encontrados de M.__test__
, y las cadenas de caracteres son tratadas como si fueran docstrings. En la salida, una clave K
en M.__test__
aparece con el nombre:
<name of M>.__test__.K
Todas las clases encontradas se buscan recursivamente de manera similar, para probar docstrings en sus métodos contenidos y clases anidadas.
¿Cómo se reconocen los ejemplos de docstring?¶
En la mayoría de los casos un copiar y pegar de una sesión de consola interactiva funciona bien, pero doctest no está intentando hacer una emulación exacta de ningún shell específico de Python.
>>> # comments are ignored
>>> x = 12
>>> x
12
>>> if x == 13:
... print("yes")
... else:
... print("no")
... print("NO")
... print("NO!!!")
...
no
NO
NO!!!
>>>
Cualquier salida esperada debe seguir inmediatamente el final de la línea '>>>'
o '...'
conteniendo el código, y la salida esperada (si la hubiera) se extiende hasta el siguiente '>>>'
o la línea en blanco.
La letra pequeña:
La salida esperada no puede contener una línea de espacios en blanco, ya que ese tipo de línea se toma para indicar el fin de la salida esperada. Si la salida esperada de verdad contiene una línea en blanco, pon
<BLANKLINE>
en tu ejemplo de doctest en cada lugar donde una línea en blanco sea esperada.Todos los caracteres de tabulación se expanden a espacios, usando paradas de tabulación de 8 -columnas. Las tabulaciones generadas por el código en pruebas no son modificadas. Ya que todas las tabulaciones en la salida de prueba son expandidas, significa que si el código de salida incluye tabulaciones, la única manera de que el doctest pueda pasar es si la opción
NORMALIZE_WHITESPACE
o directive está en efecto. Alternativamente, la prueba puede ser reescrita para capturar la salida y compararla a un valor esperado como parte de la prueba. Se llegó a este tratamiento de tabulaciones en la fuente a través de prueba y error, y ha demostrado ser la manera menos propensa a errores de manejarlos. Es posible usar un algoritmo diferente para manejar tabulaciones al escribir una claseDocTestParser
personalizada.La salida a stdout es capturada, pero no la salida a stderr (los rastreos de la excepción son capturados a través de maneras diferentes).
Si continuas una línea poniendo una barra invertida en una sesión interactiva, o por cualquier otra razón usas una barra invertida, debes usar un docstring crudo, que preservará tus barras invertidas exactamente como las escribes:
>>> def f(x): ... r'''Backslashes in a raw docstring: m\n''' >>> print(f.__doc__) Backslashes in a raw docstring: m\n
De otra manera, la barra invertida será interpretada como parte de una cadena. Por ejemplo, el
\n
arriba sería interpretado como un carácter de nueva línea. Alternativamente, puedes duplicar cada barra invertida en la versión de doctest (y no usar una cadena de caracteres cruda):>>> def f(x): ... '''Backslashes in a raw docstring: m\\n''' >>> print(f.__doc__) Backslashes in a raw docstring: m\n
La columna inicial no importa:
>>> assert "Easy!" >>> import math >>> math.floor(1.9) 1
y tantos espacios en blanco al principio se eliminan de la salida esperada como aparece en la línea
'>>>'
inicial que empezó el ejemplo.
¿Cuál es el contexto de ejecución?¶
Por defecto, cada vez que un doctest
encuentre un docstring para probar, usa una copia superficial de los globales de M
, por lo que ejecutar pruebas no cambia los globales reales del módulo, y por lo que una prueba en M
no puede dejar atrás migajas que permitan a otras pruebas trabajar. Significa que los ejemplos pueden usar libremente cualquier nombre definido en el nivel superior en M
, y nombres definidos más temprano en los docstrings siendo ejecutados. Los ejemplos no pueden ver nombres definidos en otros docstrings.
Puedes forzar el uso de tus propios diccionarios como contexto de ejecución al pasar globs=your_dict
a testmod()
o testfile()
en su lugar.
¿Y las excepciones?¶
No hay problema, siempre que el rastreo sea la única salida producida por el ejemplo: sólo copia el rastreo. 1 Ya que los rastreos contienen detalles que probablemente cambien rápidamente (por ejemplo, rutas de archivos exactas y números de línea), este es un caso donde doctest trabaja duro para ser flexible en lo que acepta.
Ejemplo simple:
>>> [1, 2, 3].remove(42)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: list.remove(x): x not in list
El doctest tiene éxito si se lanza ValueError
, con el detalle list.remove(x): x not in list
como se muestra.
La salida esperada para una excepción debe empezar con una cabecera de rastreo, que puede ser una de las siguientes dos líneas, con el mismo sangrado de la primera línea del ejemplo:
Traceback (most recent call last):
Traceback (innermost last):
La cabecera de rastreo es seguida por una pila de rastreo opcional, cuyo contenido es ignorado por doctest. La pila de rastreo es típicamente omitida, o copiada palabra por palabra de una sesión interactiva.
La pila de rastreo es seguida por la parte más interesante: la línea o líneas conteniendo el tipo de excepción y detalle. Esto es usualmente la última línea de un rastreo, pero se puede extender a través de múltiples líneas si la excepción tiene un detalle de varias líneas:
>>> raise ValueError('multi\n line\ndetail')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: multi
line
detail
Las últimas tres líneas (empezando con ValueError
) son comparados con el tipo de excepción y detalle, y el resto es ignorado.
La mejor práctica es omitir la pila de rastreo, a menos que añada valor de documentación significante al ejemplo. Por lo que el último ejemplo es probablemente mejor como:
>>> raise ValueError('multi\n line\ndetail')
Traceback (most recent call last):
...
ValueError: multi
line
detail
Note que los rastreos son tratados de manera especial. En particular, en el ejemplo reescrito, el uso de ...
es independiente de la opción ELLIPSIS
de doctest. Se pueden excluir los puntos suspensivos en ese ejemplo, así como también pueden haber tres (o trescientas) comas o dígitos, o una transcripción sangrada de un sketch de Monty Python.
Algunos detalles que debes leer una vez, pero no necesitarás recordar:
Doctest no puede adivinar si tu salida esperada vino de una excepción de rastreo o de una impresión ordinaria. Así que, un ejemplo que espera
ValueError: 42 is prime
pasará, ya sea si de hecho se lanceValueError
o si el ejemplo simplemente imprime ese texto de rastreo. En la práctica, la salida ordinaria raramente comienza con una línea de cabecera de rastreo, por lo que esto no crea problemas reales.Cada línea de la pila de rastreo (si se presenta) debe estar más sangrada que la primera línea del ejemplo, o empezar con un carácter no alfanumérico. la primera línea que sigue a la cabecera de rastreo sangrada de igual forma y empezando con un alfanumérico es considerado el inicio del detalle de la excepción. Por supuesto que esto es lo correcto para rastreos genuinos.
Cuando se especifica la opción
IGNORE_EXCEPTION_DETAIL
de doctest. todo lo que sigue a los dos puntos más a la izquierda y cualquier otra información del módulo en el nombre de la excepción se ignora.El shell interactivo omite la línea de la cabecera de rastreo para algunos
SyntaxError
. Pero doctest usa la línea de la cabecera de rastreo para distinguir excepciones de los que no son. Así que en algunos casos raros donde necesitas probar unSyntaxError
que omite la cabecera de rastreo, necesitarás poner manualmente la línea de cabecera de rastreo en tu ejemplo de prueba.
Para algunos
SyntaxError
, Python muestra la posición del carácter del error de sintaxis, usando un marcador^
:>>> 1 1 File "<stdin>", line 1 1 1 ^ SyntaxError: invalid syntax
Ya que las líneas mostrando la posición del error vienen antes del tipo de excepción y detalle, no son revisadas por doctest. Por ejemplo, el siguiente test pasaría, a pesar de que pone el marcador
^
en la posición equivocada:>>> 1 1 Traceback (most recent call last): File "<stdin>", line 1 1 1 ^ SyntaxError: invalid syntax
Banderas de Opción¶
Varias banderas de opción controlan diversos aspectos del comportamiento de doctest. Los nombres simbólicos para las banderas son proporcionados como constantes del módulo, que se pueden conectar mediante *OR* bit a bit y pasar a varias funciones. Los nombres también pueden ser usados en las directivas de doctest, y se pueden pasar a la interfaz de la línea de comandos de doctest a través de la opción -o
.
Nuevo en la versión 3.4: La opción de la línea de comandos -o
.
El primer grupo de opciones definen las semánticas de la prueba, controlando aspectos de cómo doctest decide si la salida de hecho concuerda con la salida esperada del ejemplo:
-
doctest.
DONT_ACCEPT_TRUE_FOR_1
¶ Por defecto, si un bloque de salida esperada contiene sólo
1
, se considera igual a un bloque de salida real conteniendo sólo1
otrue
, y similarmente para0
contraFalse
. Cuando se especificaDONT_ACCEPT_TRUE_FOR_1`
, no se permite ninguna sustitución. El comportamiento por defecto atiende a que Python cambió el tipo de retorno de muchas funciones de enteros a booleanos; los doctest esperando salidas «de pequeño enteros» todavía trabajan en estos casos. Esta opción probablemente se vaya, pero no por muchos años.
-
doctest.
DONT_ACCEPT_BLANKLINE
¶ Por defecto, si un bloque de salida esperada contiene una línea que sólo tiene la cadena de caracteres
<BLANKLINE>
, entonces esa línea corresponderá a una línea en blanco en la salida real. Ya que una línea en blanca auténtica delimita la salida esperada, esta es la única manera de comunicar que una línea en blanco es esperada. Cuando se especificaDONT_ACCEPT_BLANKLINE
, esta substitución no se permite.
-
doctest.
NORMALIZE_WHITESPACE
¶ Cuando se especifica, todas las secuencias de espacios en blanco (vacías y nuevas líneas) son tratadas como iguales. Cualquier secuencia de espacios en blanco dentro de la salida esperada corresponderá a cualquier secuencia de espacios en blanco dentro de la salida real. Por defecto, los espacios en blanco deben corresponderse exactamente.
NORMALIZE_WHITESPACE
es especialmente útil cuando una línea de la salida esperada es muy larga, y quieres envolverla a través de múltiples líneas en tu código fuente.
-
doctest.
ELLIPSIS
¶ Cuando se especifica, un marcador de puntos suspensivos (
...
) en la salida esperada puede corresponder a cualquier cadena de caracteres en la salida real. Esto incluye las cadenas de caracteres que abarcan límites de líneas, y cadenas de caracteres vacías, por lo que es mejor mantener su uso simple. Usos complicados pueden conducir a los mismo tipos de sorpresa de «ups, coincidió demasiado» que.*
es propenso a hacer en expresiones regulares.
-
doctest.
IGNORE_EXCEPTION_DETAIL
¶ When specified, doctests expecting exceptions pass so long as an exception of the expected type is raised, even if the details (message and fully qualified exception name) don’t match.
For example, an example expecting
ValueError: 42
will pass if the actual exception raised isValueError: 3*14
, but will fail if, say, aTypeError
is raised instead. It will also ignore any fully qualified name included before the exception class, which can vary between implementations and versions of Python and the code/libraries in use. Hence, all three of these variations will work with the flag specified:>>> raise Exception('message') Traceback (most recent call last): Exception: message >>> raise Exception('message') Traceback (most recent call last): builtins.Exception: message >>> raise Exception('message') Traceback (most recent call last): __main__.Exception: message
Note that
ELLIPSIS
can also be used to ignore the details of the exception message, but such a test may still fail based on whether the module name is present or matches exactly.Distinto en la versión 3.2:
IGNORE_EXCEPTION_DETAIL
también ignora cualquier información relacionada al módulo conteniendo la excepción bajo prueba.
-
doctest.
SKIP
¶ Cuando se especifica, no ejecuta el ejemplo del todo. Puede ser útil en contextos donde los ejemplos de doctest sirven como documentación y casos de prueba a la vez, y un ejemplo debe ser incluido para propósitos de documentación, pero no debe ser revisado. P. ej., la salida del ejemplo puede ser aleatoria, o el ejemplo puede depender de recursos que no estarían disponibles para el controlador de pruebas.
La bandera SKIP también se puede usar para temporalmente «quitar» ejemplos.
-
doctest.
COMPARISON_FLAGS
¶ Una máscara de bits o juntadas lógicamente todas las banderas de arriba.
El segundo grupo de opciones controla cómo las fallas de las pruebas son reportadas:
-
doctest.
REPORT_UDIFF
¶ Cuando se especifica, las fallas que involucran salidas multilínea esperadas y reales son mostradas usando una diferencia (diff) unificada.
-
doctest.
REPORT_CDIFF
¶ Cuando se especifica, las fallas que involucran salidas multilínea esperadas y reales se mostrarán usando una diferencia (diff) contextual.
-
doctest.
REPORT_NDIFF
¶ Cuando se especifica, las diferencias son computadas por
difflib.Differ
, usando el mismo algoritmo que la popular utilidadndiff.py
. Este es el único método que marca diferencias dentro de líneas también como a través de líneas. Por ejemplo, si una línea de salida esperada contiene el dígito1
donde la salida actual contiene la letral
, se inserta una línea con una marca de inserción marcando la posición de las columnas que no coinciden.
-
doctest.
REPORT_ONLY_FIRST_FAILURE
¶ Cuando se especifica, muestra el primer ejemplo fallido en cada doctest, pero suprime la salida para todos ejemplos restantes. Esto evitará que doctest reporte los ejemplos correctos que se rompen por causa de fallos tempranos; pero también puede esconder ejemplos incorrectos que fallen independientemente de la primera falla. Cuando se especifica
REPORT_ONLY_FIRST_FAILURE
, los ejemplos restantes aún se ejecutan, y aún cuentan para el número total de fallas reportadas, sólo se suprime la salida.
-
doctest.
FAIL_FAST
¶ Cuando se especifica, sale después del primer ejemplo fallido y no intenta ejecutar los ejemplos restantes. Por consiguiente, el número de fallas reportadas será como mucho 1. Esta bandera puede ser útil durante la depuración, ya que los ejemplos después de la primera falla ni siquiera producirán salida de depuración.
La línea de comandos de doctest acepta la opción
-f
como un atajo para-o FAIL_FAST
.Nuevo en la versión 3.4.
-
doctest.
REPORTING_FLAGS
¶ Una máscara de bits o todas las banderas de reporte arriba combinadas.
También hay una manera de registrar nombres de nuevas opciones de banderas, aunque esto no es útil a menos que intentes extender doctest
a través de herencia:
-
doctest.
register_optionflag
(name)¶ Crea una nueva bandera de opción con un nombre dado, y retorna el valor entero de la nueva bandera. se puede usar
register_optionflag()
cuando se heredaOutputChecker
oDocTestRunner
para crear nuevas opciones que sean compatibles con tus clases heredadas.register_optionflag()
siempre debe ser llamado usando la siguiente expresión:MY_FLAG = register_optionflag('MY_FLAG')
Directivas¶
Se pueden usar las directivas de doctest para modificar las banderas de opción para un ejemplo individual. Las directivas de doctest son comentarios de Python especiales que siguen el código fuente de un ejemplo:
directive ::= "#" "doctest:"directive_options
directive_options ::=directive_option
(","directive_option
)* directive_option ::=on_or_off
directive_option_name
on_or_off ::= "+" | "-" directive_option_name ::= "DONT_ACCEPT_BLANKLINE" | "NORMALIZE_WHITESPACE" | ...
No se permite el espacio en blanco entre el +
o -
y el nombre de la opción de directiva (directive option name). El nombre de la opción de directiva puede ser cualquiera de los nombres de las banderas de opciones explicadas arriba.
Las directivas de doctest de un ejemplo modifican el comportamiento de doctest para ese único ejemplo. Usa +
para habilitar el comportamiento nombrado, o -
para deshabilitarlo.
For example, this test passes:
>>> print(list(range(20))) # doctest: +NORMALIZE_WHITESPACE
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
Without the directive it would fail, both because the actual output doesn’t have two blanks before the single-digit list elements, and because the actual output is on a single line. This test also passes, and also requires a directive to do so:
>>> print(list(range(20))) # doctest: +ELLIPSIS
[0, 1, ..., 18, 19]
Multiple directives can be used on a single physical line, separated by commas:
>>> print(list(range(20))) # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
[0, 1, ..., 18, 19]
If multiple directive comments are used for a single example, then they are combined:
>>> print(list(range(20))) # doctest: +ELLIPSIS
... # doctest: +NORMALIZE_WHITESPACE
[0, 1, ..., 18, 19]
As the previous example shows, you can add ...
lines to your example
containing only directives. This can be useful when an example is too long for
a directive to comfortably fit on the same line:
>>> print(list(range(5)) + list(range(10, 20)) + list(range(30, 40)))
... # doctest: +ELLIPSIS
[0, ..., 4, 10, ..., 19, 30, ..., 39]
Tenga en cuenta que ya que todas las opciones están deshabilitadas por defecto, y las directivas sólo aplican a los ejemplos en los que aparecen, habilitarlas (a través de +
en la directiva) usualmente es la única opción significativa. Sin embargo, las banderas de opciones también pueden ser pasadas a funciones que ejecutan doctests, estableciendo valores por defecto diferentes. En tales casos, deshabilitar una opción a través de -
en una directiva puede ser útil.
Advertencias¶
doctest
es serio acerca de requerir coincidencias exactas en la salida esperada. Si incluso un solo carácter no coincide, el test falla. Esto probablemente te sorprenderá algunas veces, mientras aprendes exactamente lo que Python asegura y no asegura sobre la salida. Por ejemplo, cuando se imprime un conjunto, Python no asegura que el elemento sea impreso en ningún orden particular, por lo que una prueba como
>>> foo()
{"Hermione", "Harry"}
¡es vulnerable! Una solución puede ser hacer
>>> foo() == {"Hermione", "Harry"}
True
es su lugar. Otra es hacer
>>> d = sorted(foo())
>>> d
['Harry', 'Hermione']
Existen otros casos, pero ya captas la idea.
Another bad idea is to print things that embed an object address, like
>>> id(1.0) # certain to fail some of the time
7948648
>>> class C: pass
>>> C() # the default repr() for instances embeds an address
<C object at 0x00AC18F0>
The ELLIPSIS
directive gives a nice approach for the last example:
>>> C() # doctest: +ELLIPSIS
<C object at 0x...>
Los números de coma flotante también son sujetos a pequeñas variaciones de la salida a través de las plataformas, porque Python defiere a la librería C de la plataforma para el formato de flotantes, y las librerías de C varían extensamente en calidad aquí.
>>> 1./7 # risky
0.14285714285714285
>>> print(1./7) # safer
0.142857142857
>>> print(round(1./7, 6)) # much safer
0.142857
Números de la forma I/2.**J
son seguros a lo largo de todas las plataformas, y yo frecuentemente planeo ejemplos de doctest para producir números de esa forma:
>>> 3./4 # utterly safe
0.75
Las facciones simples también son más fáciles de entender para las personas, y eso conduce a una mejor documentación.
API básica¶
Las funciones testmod()
y testfile()
proporcionan una interfaz simple para doctest que debe ser suficiente para la mayoría de los usos básicos. Para una introducción menos formal a estas funciones, véase las secciones Uso simple: verificar ejemplos en docstrings y Uso Simple: Verificar ejemplos en un Archivo de Texto.
-
doctest.
testfile
(filename, module_relative=True, name=None, package=None, globs=None, verbose=None, report=True, optionflags=0, extraglobs=None, raise_on_error=False, parser=DocTestParser(), encoding=None)¶ Todos los argumentos excepto filename son opcionales, y deben ser especificados en forma de palabras claves.
Prueba los ejemplos en el archivo con nombre filename. Retorna
(failure_count, test_count)
.El argumento opcional module_relative especifica cómo el nombre de archivo debe ser interpretado:
Si module_relative es
True
(el valor por defecto), entonces filename especifica una ruta relativa al módulo que es independiente del SO. Por defecto, esta ruta es relativa al directorio del módulo que lo invoca; pero si el argumento package es especificado, entonces es relativo a ese paquete. Para asegurar la independencia del SO, filename debe usar caracteres/
para separar segmentos, y no puede ser una ruta absoluta (por ejemplo., no puede empezar con/
).Si module_relative es
False
, entonces filename especifica una ruta especifica del SO. La ruta puede ser absoluta o relativa; las rutas relativas son resueltas con respecto al directorio de trabajo actual.
El argumento opcional name proporciona el nombre de la prueba; por defecto, o si es
None
, se usaos.path.basename(filename)
.El argumento opcional package es un paquete de Python o el nombre de una paquete de Python cuyo directorio debe ser usado como el directorio base para un nombre de archivo relativo al módulo. Si no se especifica ningún paquete, entonces el directorio del módulo que invoca se usa como el directorio base para los nombres de archivos relativos al módulo. Es un error especificar package si module_relative es
False
.El argumento opcional globs proporciona un diccionario a ser usado como los globales cuando se ejecuten los ejemplos. Se crea una nueva copia superficial de este diccionario para el doctest, por lo que sus ejemplos empiezan con una pizarra en blanco. Por defecto, o si es
None
, se usa un nuevo diccionario vacío.El argumento opcional extraglobs proporciona un diccionario mezclado con los globales usados para ejecutar ejemplos. Funciona como
dict.update()
: si globs y extraglobs tienen una clave en común, el valor asociado en extraglobs aparece en el diccionario combinado. Por defecto, o si esNone
, no se usa ninguna variable global. Es una característica avanzada que permite la parametrización de doctests. Por ejemplo, un doctest puede ser escribo para una clase base, usando un nombre genérico para la clase, y luego reusado para probar cualquier número de clases heredadas al pasar un diccionario de extraglobs mapeando el nombre genérico a la clase heredada para ser probada.El argumento opcional verbose imprime un montón de cosas si es verdadero, e imprime sólo las fallas si es falso; por defecto, o si es
None
, es verdadero si y sólo si'-v'
está ensys.argv
.El argumento opcional report imprime un resumen al final cuando es verdadero; si no, no imprime nada al final. En modo verboso (verbose), el resumen es detallado; si no, el resumen es muy corto (de hecho, vacío si todos las pruebas pasan).
El argumento opcional optionflags (valor por defecto 0) toma las banderas de opciones juntadas lógicamente por un OR. Véase la sección Banderas de Opción.
El argumento opcional raise_on_error tiene como valor por defecto false. Si es true, se lanza una excepción sobre la primera falla o excepción no esperada en un ejemplo. Esto permite que los fallos sean depurados en un análisis a posteriori. El comportamiento por defecto es continuar corriendo los ejemplos.
El argumento opcional parser especifica un
DocTestParser
(o subclase) que debe ser usado para extraer las pruebas de los archivos. Su valor por defecto es un analizador sintáctico normal (i.e.,DocTestParser()
).El argumento opcional encoding especifica una codificación que debe ser usada para convertir el archivo a unicode.
-
doctest.
testmod
(m=None, name=None, globs=None, verbose=None, report=True, optionflags=0, extraglobs=None, raise_on_error=False, exclude_empty=False)¶ Todos los argumentos son opcionales, y todos excepto por m deben ser especificados en forma de palabras claves.
Prueba los ejemplos en los docstring de las funciones y clases alcanzables desde el módulo m (o desde el módulo
__main__
si m no es proporcionado o esNone
), empezando conm.__doc__
.También prueba los ejemplos alcanzables desde el diccionario de
m.__test__
, si existe y no esNone
.m.__test__
mapea los nombres (cadenas de caracteres) a funciones, clases y cadenas de caracteres; se buscan los ejemplos de las funciones y clases; se buscan las cadenas de caracteres directamente como si fueran docstrings.Sólo se buscan los docstrings anexados a los objetos pertenecientes al módulo m.
Retorna
(failure_count, test_count)
.El argumento opcional name proporciona el nombre del módulo; por defecto, o si es
None
, se usam.__name__
.El argumento opcional exclude_empty es por defecto false. Si es verdadero, se excluyen los objetos por los cuales no se encuentren doctest. El valor por defecto es un hack de compatibilidad hacia atrás, por lo que el código que use
doctest.master.summarize()
en conjunto contestmod()
continua obteniendo la salida para objetos sin pruebas. El argumento exclude_empty para el más nuevo constructorDocTestFinder
es por defecto verdadero.Los argumentos opcionales extraglobs, verbose, report, optionflags, raise_on_error, y globs son los mismos en cuanto a la función
testfile()
arriba, excepto que globs es por defectom.__dict__
.
-
doctest.
run_docstring_examples
(f, globs, verbose=False, name='NoName', compileflags=None, optionflags=0)¶ Prueba los ejemplos asociados con el objeto f; por ejemplo, f puede ser una cadena de caracteres, un módulo, una función, o un objeto clase.
Una copia superficial del diccionario del argumento globs se usa para la ejecución del contexto.
Se usa el argumento opcional name en mensajes de fallos, y por defecto es
"NoName"
.Si el argumento opcional verbose es verdadero, la salida se genera incluso si no hay fallas. Por defecto, la salida se genera sólo en caso de la falla de un ejemplo.
El argumento opcional compileflags proporciona el conjunto de banderas que se deben usar por el compilador de Python cuando se corran los ejemplos. Por defecto, o si es
None
, las banderas se deducen correspondiendo al conjunto de características futuras encontradas en globs.El argumento opcional optionflags trabaja con respecto a la función
testfile()
de arriba.
API de unittest¶
Mientras crece tu colección de módulos probados con doctest, vas a querer una forma de ejecutar todos sus doctests sistemáticamente. doctest
proporciona dos funciones que se pueden usar para crear un banco de pruebas (test suite) de unittest
desde módulos y archivos de texto que contienen doctests. Para integrarse con el descubrimiento de pruebas de unittest
, incluye una función load_tests()
en tu módulo de pruebas:
import unittest
import doctest
import my_module_with_doctests
def load_tests(loader, tests, ignore):
tests.addTests(doctest.DocTestSuite(my_module_with_doctests))
return tests
Hay dos funciones principales para crear instancias de unittest.TestSuite
desde los archivos de texto y módulos con doctests:
-
doctest.
DocFileSuite
(*paths, module_relative=True, package=None, setUp=None, tearDown=None, globs=None, optionflags=0, parser=DocTestParser(), encoding=None)¶ Convierte las pruebas de doctest de uno o más archivos de texto a una
unittest.TestSuite
.El
unittest.TestSuite
que se retorne será ejecutado por el framework de unittest y ejecuta los ejemplos interactivos en cada archivo. Si un ejemplo en cualquier archivo falla, entonces la prueba unitaria sintetizada falla, y una excepciónfailureException
se lanza mostrando el nombre del archivo conteniendo la prueba y un número de línea (algunas veces aproximado).Pasa una o más rutas (como cadenas de caracteres) a archivos de texto para ser examinados.
Se pueden proporcionar las opciones como argumentos por palabra clave:
El argumento opcional module_relative especifica cómo los nombres de archivos en paths se deben interpretar:
Si module_relative is
True
(el valor por defecto), entonces cada archivo de nombre en paths especifica una ruta relativa al módulo independiente del SO. Por defecto, esta ruta es relativa al directorio del módulo lo está invocando; pero si se especifica el argumento package, entonces es relativo a ese paquete. Para asegurar la independencia del SO, cada nombre de archivo debe usar caracteres/
para separar los segmentos de rutas, y puede no ser una ruta absoluta (i.e., puede no empezar con/
).Si module_relative es
False
, entonces cada archivo de nombre en paths especifica una ruta especifica al SO. La ruta puede ser absoluta o relativa; las rutas relativas son resueltas con respecto a directorio de trabajo actual.
El argumento opcional package es un paquete de Python o el nombre de un paquete de Python cuyo directorio debe ser usado como el directorio base para los nombres de archivos relativos al módulo en paths. Si no se especifica ningún paquete, entonces el directorio del módulo que lo está invocando se usa como el directorio base para los archivos de nombres relativos al módulo. Es un error especificar package si module_relative es
False
.El argumento opcional setUp especifica una función de configuración para el banco de pruebas. Es invocado antes de ejecutar las pruebas en cada archivo. La función setUp se pasará a un objeto
DocTest
. La función setUp puede acceder a las variables globales de prueba como el atributo globs de la prueba pasada.El argumento opcional tearDown especifica una función de destrucción para el banco de pruebas. Es invocado después de ejecutar las pruebas en cada archivo. Se pasará un objeto
DocTest
a la función tearDown. La función setUp de configuración puede acceder a los globales de la prueba como el atributo globs de la prueba pasada.El argumento opcional globs es un diccionario que contiene las variables globales iniciales para las pruebas. Se crea una nueva copia de este diccionario para cada prueba. Por defecto, globs es un nuevo diccionario vacío.
El argumento opcional optionflags especifica las opciones de doctest por defecto para las pruebas, creado al juntar lógicamente las opciones de bandera individuales. Véase la sección Banderas de Opción. Véase la función
set_unittest_reportflags()
abajo para una mejor manera de definir las opciones de informe.El argumento opcional parser especifica un
DocTestParser
(o subclase) que debe ser usado para extraer las pruebas de los archivos. Su valor por defecto es un analizador sintáctico normal (i.e.,DocTestParser()
).El argumento opcional encoding especifica una codificación que debe ser usada para convertir el archivo a unicode.
Se añade el global
__file__
a los globales proporcionados a los doctests cargados desde un archivo de texto usandoDocFileSuite()
.
-
doctest.
DocTestSuite
(module=None, globs=None, extraglobs=None, test_finder=None, setUp=None, tearDown=None, checker=None)¶ Convierte las pruebas de doctest para un módulo a un
unittest.TestSuite
.El
unittest.TestSuite
que se retorne será ejecutado por el framework de unittest y corre cada doctest en el módulo. Si cualquiera de los doctests falla, entonces la prueba unitaria combinada falla, y se lanza una excepciónfailureException
mostrando el nombre del archivo que contiene la prueba y un número de línea (a veces aproximado).El argumento opcional module proporciona el módulo a probar. Puede ser un objeto de módulo o un nombre (posiblemente punteado) de módulo. Si no se especifica, se usa el módulo que invoca esta función.
El argumento opcional globs es un diccionario que contiene las variables globales iniciales para las pruebas. Se crea una nueva copia de este diccionario para cada prueba. Por defecto, globs es un nuevo diccionario vacío.
El argumento opcional extraglobs especifica un conjunto de variables globales adicionales que son mezcladas con globs. Por defecto, no se usa ningún global adicional.
El argumento opcional test_finder es el objeto
DocTestFinder
(o un reemplazo directo) que se usa para extraer doctests desde el módulo.Los argumentos opcionales setUp, tearDown, y optionflags son lo mismo con respecto a la función
DocFileSuite()
arriba.Esta función usa la misma técnica de búsqueda que
testmod()
.Distinto en la versión 3.5:
DocTestSuite()
retorna ununittest.TestSuite
vacío si module no contiene ningún docstring en vez de lanzar unValueError
.
Por detrás, DocTestSuite()
crea un unittest.TestSuite
de las instancias de doctest.DocTestCase
, y DocTestCase
es una subclase de unittest.TestCase
. DocTestCase
no está documentado aquí (es un detalle interno), pero estudiar su código puede responder preguntas sobre los detalles exactos de la integración de unittest
.
De manera similar, DocFileSuite()
crea un unittest.TestSuite
de las instancias de doctest.DocFileCase
, y DocFileCase
es una subclase de DocTestCase
.
Por lo que ambas formas de crear un unittest.TestSuite
ejecutan instancias de DocTestCase
. Esto es importante por una razón sutil: cuando ejecutas las funciones de doctest
por ti mismo, puedes controlar las opciones de doctest
en uso directamente, al pasar las banderas de opciones a las funciones de doctest
. Sin embargo, si estás escribiendo un framework de unittest
, básicamente unittest
controla cuándo y cómo se ejecutan las pruebas. El autor del framework típicamente, quiere controlar las opciones de reporte de doctest
(quizás, p.ej., especificadas por las opciones de la línea de comandos), pero no hay forma de pasar opciones a través de unittest
al probador de ejecución (test runner) de doctest
.
Por esta razón, doctest
también admite una noción de banderas de informe de doctest
específicas para la compatibilidad con unittest
, a través de esta función:
-
doctest.
set_unittest_reportflags
(flags)¶ Establece las banderas de informe de
doctest
a usar.El argumento flags toma la combinación por el operador OR de las banderas de opciones. Véase la sección Banderas de Opción. Sólo se pueden usar las «banderas de informe».
Esta es una configuración global del módulo, y afecta a todos los doctests futuros a ejecutar por
unittest
: el métodorunTest()
deDocTestCase
revisa las banderas de opciones especificadas para el caso de prueba cuando la instancia deDocTestCase
fue construida. Si no se especificó ninguna bandera de informe (que es el caso típico y esperado), las banderas de informe -pertenecientes adoctest
- deunittest
son combinadas por la operación Or en las banderas de opciones, y las banderas de opciones aumentadas se pasan a la instancia deDocTestRunner
creada para ejecutar los doctest. Si se especificó alguna bandera de informe cuando elDocTestCase
fue construido, se ignoran las banderas de informe -pertenecientes adoctest
- deunittest
.La función retorna el valor de las banderas de informe de
unittest
en efecto antes de que la función fuera invocada.
API avanzada¶
La API básica es un simple envoltorio que sirve para hacer los doctest fáciles de usar. Es bastante flexible, y debe cumplir las necesidades de la mayoría de los usuarios; si requieres un control más preciso en las pruebas, o deseas extender las capacidades de doctest, entonces debes usar la API avanzada.
La API avanzada gira en torno a dos clases contenedoras, que se usan para guardar los ejemplos interactivos extraídos de los casos doctest:
Example
: Un statement de Python, emparejado con su salida esperada.DocTest
: Una colección de clasesExample
, típicamente extraídos de un sólo docstring o archivo de texto.
Se definen clases de procesamiento adicionales para encontrar, analizar sintácticamente, y ejecutar, y comprobar ejemplos de doctest:
DocTestFinder
: Encuentra todos los docstrings en un módulo dado, y usa unDocTestParser
para crear unDocTest
de cada docstring que contiene ejemplos interactivos.DocTestParser
: Crea un objetoDocTest
de una cadena de caracteres (tal como un docstring de un objeto).DocTestRunner
: Ejecuta los ejemplos en unDocTest
, y usa unOutputChecker
para verificar su salida.OutputChecker
: Compara la salida real de un ejemplo de doctest con la salida esperada, y decide si coinciden.
Las relaciones entre estas clases de procesamiento se resumen en el siguiente diagrama:
list of:
+------+ +---------+
|module| --DocTestFinder-> | DocTest | --DocTestRunner-> results
+------+ | ^ +---------+ | ^ (printed)
| | | Example | | |
v | | ... | v |
DocTestParser | Example | OutputChecker
+---------+
Objetos DocTest¶
-
class
doctest.
DocTest
(examples, globs, name, filename, lineno, docstring)¶ Una colección de ejemplos de doctest que deben ejecutarse en un sólo nombre de espacios. Se usan los argumentos del constructor para inicializar los atributos de los mismos nombres.
DocTest
define los siguientes atributos. Son inicializados por el constructor, y no deben ser modificados directamente.-
examples
¶ Una lista de objetos
Example
codificando los ejemplos interactivos de Python individuales que esta prueba debe ejecutar.
-
globs
¶ El nombre de espacios (alias globals) en que los ejemplos se deben ejecutar. Este es un diccionario que mapea nombres a valores. Cualquier cambio al nombre de espacios hecho por los ejemplos (tal como juntar nuevas variables) se reflejará en
globs
después de que se ejecute la prueba.
-
name
¶ Un nombre de cadena de caracteres que identifica el
DocTest
. Normalmente, este es el nombre del objeto o archivo del que se extrajo la prueba.
-
filename
¶ El nombre del archivo del que se extrajo este
DocTest
; oNone
si el nombre del archivo se desconoce, o siDocTest
no se extrajo de un archivo.
-
lineno
¶ El número de línea dentro de
filename
donde esteDocTest
comienza, oNone
si el número de línea no está disponible. Este número de línea es comienza en 0 con respecto al comienzo del archivo.
-
docstring
¶ La cadena de caracteres del que se extrajo la cadena, o
None
si la cadena no está disponible, o si la prueba no se extrajo de una cadena de caracteres.
-
Objetos Example¶
-
class
doctest.
Example
(source, want, exc_msg=None, lineno=0, indent=0, options=None)¶ Un sólo ejemplo interactivo, que consta de una sentencia de Python y su salida esperada. Los argumentos del constructor se usan para inicializar los atributos del mismo nombre.
La clase
Example
define los siguientes atributos. Son inicializados por el constructor, y no deben ser modificados directamente.-
source
¶ Una cadena de caracteres que contiene el código fuente del ejemplo. Este código fuente consiste de una sola sentencia Python, y siempre termina en una nueva línea; el constructor añade una nueva línea cuando sea necesario.
-
want
¶ La salida esperada de ejecutar el código fuente del ejemplo (o desde la salida estándar, o un seguimiento en caso de una excepción).
wants
termina con una nueva línea a menos que no se espera ninguna salida, en cuyo caso es una cadena vacía. El constructor añade una nueva línea cuando sea necesario.
-
exc_msg
¶ El mensaje de excepción que el ejemplo genera, si se espera que el ejemplo genere una excepción; o
None
si no se espera que genere una excepción. Se compara este mensaje de excepción con el valor de retorno detraceback.format_exception_only()
.exc_msg
termina con una nueva línea a menos que seaNone
. El constructor añade una nueva línea si se necesita.
-
lineno
¶ El número de línea dentro de la cadena de caracteres que contiene este ejemplo donde el ejemplo comienza. Este número de línea comienza en 0 con respecto al comienzo de la cadena que lo contiene.
-
indent
¶ La sangría del ejemplo en la cadena que lo contiene; i.e., el número de caracteres de espacio que preceden la primera entrada del ejemplo.
-
options
¶ Un diccionario que mapea de las banderas de opciones a
True
oFalse
, que se usa para anular las opciones por defecto para este ejemplo. Cualquier bandera de opción que no contiene este diccionario se deja con su valor por defecto (como se especifica por losoptionflags
deDocTestRunner
). Por defecto, no se establece ninguna opción.
-
Objetos DocTestFinder¶
-
class
doctest.
DocTestFinder
(verbose=False, parser=DocTestParser(), recurse=True, exclude_empty=True)¶ Una clase de procesamiento que se usa para extraer los
DocTest
que son relevantes para un objeto dado, desde su docstring y los docstring de sus objetos contenidos. Se puede extraer losDocTest
de los módulos, clases, funciones, métodos, métodos estáticos, métodos de clase, y propiedades.Se puede usar el argumento opcional verbose para mostrar los objetos buscados por finder. Su valor por defecto es
False
(ninguna salida).El argumento opcional parser especifica el objeto
DocTestParser
(o un reemplazo directo) que se usa para extraer doctests desde docstrings.Si el argumento opcional recurse es falso, entonces el método
DocTestFinder.find()
sólo examinará el objeto dado, y no cualquier objeto contenido.Si el argumento opcional exclude_empty es falso, entonces
DocTestFinder.find()
incluirá pruebas para objetos con docstrings vacíos.DocTestFinder
define los siguientes métodos:-
find
(obj[, name][, module][, globs][, extraglobs])¶ Retorna una lista de los
Doctest
que se definen por el docstring de obj, o por cualquiera de los docstring de sus objetos contenidos.El argumento opcional name especifica el nombre del objeto; este nombre será usado para construir los nombres de los
DocTest
retornados. Si name no se especifica, entonces se usaobj.__name__
.El parámetro opcional module es el módulo que contiene el objeto dado. Si no se especifica el módulo o si es
None
, entonces el buscador de pruebas tratará de determinar automáticamente el módulo correcto. Se usa el módulo del objeto:Como un espacio de nombres por defecto, si no se especifica globs.
Para evitar que DocTestFinder extraiga DocTests desde objetos que se importan desde otros módulos. (Se ignoran objetos contenidos con módulos aparte de module.)
Para encontrar el nombre del archivo conteniendo el objeto.
Para ayudar a encontrar el número de línea del objeto dentro de su archivo.
Si module es falso, no se hará ningún intento de encontrar el módulo. Es poco claro, de uso mayormente para probar doctest en si mismo: si module es
False
, o esNone
pero no se puede encontrar automáticamente, entonces todos los objetos se consideran que pertenecen al módulo (inexistente), por lo que todos los objetos contenidos se buscarán (recursivamente) por doctests.Los globales para cada
DocTest
se forma al combinar globs y extraglobs (los enlaces en extraglobs anulan los enlaces en globs). Se crea una nueva copia superficial del diccionario de globales para cadaDocTest
. Si globs no se especifica, entonces su valor por defecto es el __dict__ del módulo, si se especifica, o es{}
de lo contrario, si extraglobs no se especifica, entonces su valor por defecto es{}
.
-
Objetos DocTestParser¶
-
class
doctest.
DocTestParser
¶ Un clase de procesamiento usada para extraer ejemplos interactivos de una cadena de caracteres, y usarlos para crear un objeto
DocTest
.DocTestParser
define los siguientes métodos:-
get_doctest
(string, globs, name, filename, lineno)¶ Extrae todos los ejemplos de doctest de una cadena dada, y los recolecta en un objeto
DocTest
.globs, name, filename, y lineno son atributos para el nuevo objeto
DocTest
. Véase la documentación deDocTest
para más información.
-
get_examples
(string, name='<string>')¶ Extrae todos los ejemplos de la cadena de caracteres dada, y los retorna como una lista de objetos
Example
. Los números de línea empiezan en 0. El argumento opcional name es una nombre identificando esta cadena, y sólo es usada para mensajes de errores.
-
parse
(string, name='<string>')¶ Divide el string dado en ejemplos y texto intermedio, y los retorna como una lista que alterna entre objetos
Example
y cadenas de caracteres. Los números de línea para los objetosExample
empiezan en 0. El argumento opcional name es un nombre identificando esta cadena, y sólo se usa en mensajes de error.
-
Objetos DocTestRunner¶
-
class
doctest.
DocTestRunner
(checker=None, verbose=None, optionflags=0)¶ Una clase de procesamiento usada para ejecutar y verificar los ejemplos interactivos en un
DocTest
.La comparación entre salidas esperadas y salidas reales se hace por un
OutputChecker
. Esta comparación puede ser personalizada con un número de banderas de opción; véase la sección Banderas de Opción para más información. Si las banderas de opción son insuficientes, entonces la comparación también puede ser personalizada al pasar una subclase deOutputChecker
al constructor.La salida de la pantalla del test runner se puede controlar de dos maneras. Primero, se puede pasar una función de salida a
TestRunner.run()
; esta función se invocará con cadenas que deben mostrarse. Su valor por defecto essys.stdout.write
. Si no es suficiente capturar el resultado, entonces la salida de la pantalla también se puede personalizar al heredar de DocTestRunner, y sobreescribir los métodosreport_start()
,report_success()
,report_unexpected_exception()
, yreport_failure()
.El argumento por palabra clave opcional checker especifica el objeto
OutputChecker
(o un reemplazo directo) que se debe usar para comparar las salidas esperadas con las salidas reales de los ejemplos de doctest.El argumento por palabra clave opcional verbose controla la verbosidad de
DocTestRunner
. Si verbose esTrue
, entonces la información de cada ejemplo se imprime , mientras se ejecuta. Si verbose esFalse
, entonces sólo las fallas se imprimen. Si verbose no se especifica, o esNone
, entonces la salida verbosa se usa si y sólo se usa el modificador de la línea de comandos``-v``.El argumento por palabra clave opcional optionflags se puede usar para controlar cómo el test runner compara la salida esperada con una salida real, y cómo muestra las fallas. Para más información, véase la sección Banderas de Opción.
DocTestParser
define los siguientes métodos:-
report_start
(out, test, example)¶ Notifica que el test runner está a punto de procesar el ejemplo dado. Este método es proporcionado para permitir que clases heredadas de
DocTestRunner
personalicen su salida; no debe ser invocado directamente.example es el ejemplo a punto de ser procesado. test es la prueba que contiene a example. out es la función de salida que se pasó a
DocTestRunner.run()
.
-
report_success
(out, test, example, got)¶ Notifica que el ejemplo dado se ejecutó correctamente. Este método es proporcionado para permitir que las clases heredadas de
DocTestRunner
personalicen su salida; no debe ser invocado directamente.example es el ejemplo a punto de ser procesado. got es la salida real del ejemplo. test es la prueba conteniendo example. out es la función de salida que se pasa a
DocTestRunner.run()
.
-
report_failure
(out, test, example, got)¶ Notifica que el ejemplo dado falló. Este método es proporcionado para permitir que clases heredadas de
DocTestRunner
personalicen su salida; no debe ser invocado directamente.example es el ejemplo a punto de ser procesado. got es la salida real del ejemplo. test es la prueba conteniendo example. out es la función de salida que se pasa a
DocTestRunner.run()
.
-
report_unexpected_exception
(out, test, example, exc_info)¶ Notifica que el ejemplo dado lanzó una excepción inesperada. Este método es proporcionado para permitir que las clases heredadas de
DocTestRunner
personalicen su salida; no debe ser invocado directamente.example es el ejemplo a punto de ser procesado, exc_info es una tupla que contiene información sobre la excepción inesperada (como se retorna por
sys.exc_info()
). test es la prueba conteniendo example. out es la función de salida que debe ser pasada aDocTestRunner.run()
.
-
run
(test, compileflags=None, out=None, clear_globs=True)¶ Ejecuta los ejemplos en test (un objeto
DocTest
), y muestra los resultados usando función de escritura out.Los ejemplo se ejecutan en el espacio de nombres
test.globs
. Si clear_globs es verdadero (el valor por defecto), entonces este espacio de nombres será limpiado después de la prueba se ejecute, para ayudar con la colección de basura. Si quisieras examinar el espacio de nombres después de que la prueba se complete, entonces use clear_globs=False.compileflags da el conjunto de banderas que se deben usar por el compilador de Python cuando se ejecutan los ejemplos. Si no se especifica, entonces su valor por defecto será el conjunto de banderas de future-import que aplican a globs.
La salida de cada ejemplo es revisada usando el output checker del
DocTestRunner
, y los resultados se formatean por los métodos deDocTestRunner.report_*()
.
-
summarize
(verbose=None)¶ Imprime un resumen de todos los casos de prueba que han sido ejecutados por este DocTestRunner, y retorna un named tuple
TestResults(failed, attempted)
.El argumento opcional verbose controla qué tan detallado es el resumen. Si no se especifica la verbosidad, entonces se usa la verbosidad de
DocTestRunner
.
-
Objetos OutputChecker¶
-
class
doctest.
OutputChecker
¶ Una clase que se usa para verificar si la salida real de un ejemplo de doctest coincide con la salida esperada.
OutputChecker
define dos métodos:check_output()
, que compara un par de salidas dadas, y retornaTrue
si coinciden; youtput_difference()
, que retorna una cadena que describe las diferencias entre las dos salidas.OutputChecker
define los siguientes métodos:-
check_output
(want, got, optionflags)¶ Retorna
True
si y sólo si la salida real de un ejemplo (got) coincide con la salida esperada (want). Siempre se considera que estas cadenas coinciden si son idénticas; pero dependiendo de qué banderas de opción el test runner esté usando, varias coincidencias inexactas son posibles. Véase la sección Banderas de Opción para más información sobre las banderas de opción.
-
output_difference
(example, got, optionflags)¶ Retorna una cadena que describe las diferencias entre la salida esperada para un ejemplo dado (example) y la salida real (got). optionflags es el conjunto de banderas de opción usado para comparar want y got.
-
Depuración¶
Doctest proporciona varios mecanismos para depurar los ejemplos de doctest:
Varias funciones convierten los doctest en programas de Python ejecutables, que pueden ser ejecutadas bajo el depurador de Python,
pdb
.La clase
DebugRunner
es una subclase deDocTestRunner
que lanza una excepción por el primer ejemplo fallido, conteniendo información sobre ese ejemplo. Esta información se puede usar para realizar depuración a posteriori en el ejemplo.Los casos de
unittest
generados porDocTestSuite()
admiten el métododebug()
definido porunittest.TestCase
.Puedes añadir una llamada a
pdb.set_trace()
en un ejemplo de doctest, y bajarás al depurador de Python cuando esa línea sea ejecutada. Entonces puedes inspeccionar los valores de las variables, y demás. Por ejemplo, supongamos quea.py
contiene sólo este docstring de módulo:""" >>> def f(x): ... g(x*2) >>> def g(x): ... print(x+3) ... import pdb; pdb.set_trace() >>> f(3) 9 """
Entonces una sesión interactiva puede lucir como esta:
>>> import a, doctest >>> doctest.testmod(a) --Return-- > <doctest a[1]>(3)g()->None -> import pdb; pdb.set_trace() (Pdb) list 1 def g(x): 2 print(x+3) 3 -> import pdb; pdb.set_trace() [EOF] (Pdb) p x 6 (Pdb) step --Return-- > <doctest a[0]>(2)f()->None -> g(x*2) (Pdb) list 1 def f(x): 2 -> g(x*2) [EOF] (Pdb) p x 3 (Pdb) step --Return-- > <doctest a[2]>(1)?()->None -> f(3) (Pdb) cont (0, 3) >>>
Funciones que convierten los doctest a código de Python, y posiblemente ejecuten el código sintetizado debajo del depurador:
-
doctest.
script_from_examples
(s)¶ Convierte texto con ejemplos a un script.
El argumento s es una cadena que contiene los ejemplos de doctest. La cadena se convierte a un script de Python, donde los ejemplos de doctest en s se convierten en código regular, y todo lo demás se convierte en comentarios de Python. El script generado se retorna como una cadena: Por ejemplo,
import doctest print(doctest.script_from_examples(r""" Set x and y to 1 and 2. >>> x, y = 1, 2 Print their sum: >>> print(x+y) 3 """))
muestra:
# Set x and y to 1 and 2. x, y = 1, 2 # # Print their sum: print(x+y) # Expected: ## 3
Esta función se usa internamente por otras funciones (véase más abajo), pero también pueden ser útiles cuando quieres transformar una sesión de Python interactiva en un script de Python.
-
doctest.
testsource
(module, name)¶ Convierte el doctest para un objeto en un script.
El argumento module es un objeto módulo, o un nombre por puntos de un módulo, que contiene el objeto cuyos doctest son de interés. El argumento name es el nombre (dentro del módulo) del objeto con los doctest de interés. El resultado es una cadena de caracteres, que contiene el docstring del objeto convertido en un script de Python, como se describe por
script_from_examples()
arriba. Por ejemplo, si el móduloa.py
contiene un función de alto nivelf()
, entoncesimport a, doctest print(doctest.testsource(a, "a.f"))
imprime una versión de script del docstring de la función
f()
, con los doctest convertidos en código, y el resto puesto en comentarios.
-
doctest.
debug
(module, name, pm=False)¶ Depura los doctest para un objeto.
Los argumentos module y name son los mismos que para la función
testsource()
arriba. El script de Python sintetizado para el docstring del objeto nombrado es escrito en un archivo temporal, y entonces ese archivo es ejecutado bajo el control del depurador de PYthon,pdb
.Se usa una copia superficial de
module.__dict__
para el contexto de ejecución local y global.El argumento opcional pm controla si se usa la depuración post-mortem. Si pm tiene un valor verdadero, el archivo de script es ejecutado directamente, y el depurador está involucrado sólo si el script termina a través del lanzamiento de una excepción. Si lo hace, entonces la depuración post-mortem es invocada, a través de
pdb.post_mortem()
, pasando el objeto de rastreo desde la excepción sin tratar. Si no se especifica pm, o si es falso, el script se ejecuta bajo el depurador desde el inicio, a través de una llamada deexec()
apropiada apdb.run()
.
-
doctest.
debug_src
(src, pm=False, globs=None)¶ Depura los doctest en una cadena de caracteres.
Es como la función function
debug()
arriba, excepto que una cadena de caracteres que contiene los ejemplos de doctest se especifica directamente, a través del argumento src.El argumento opcional pm tiene el mismo significado como en la función
debug()
arriba.El argumento opcional globs proporciona un diccionario a usar como contexto de ejecución local y global. Si no se especifica, o es
None
, se usa un diccionario vacío. Si se especifica, se usa una copia superficial del diccionario.
La clase DebugRunner
, y las excepciones especiales que puede lanzar, son de más interés a los autores de frameworks de pruebas, y sólo serán descritos brevemente aquí. Véase el código fuente, y especialmente el docstring de DebugRunner
(¡que es un doctest!) para más detalles:
-
class
doctest.
DebugRunner
(checker=None, verbose=None, optionflags=0)¶ Una subclase de
DocTestRunner
que lanza una excepción tan pronto como se encuentra una falla. Si ocurre una excepción inesperada, se lanza una excepciónUnexpectedException
, conteniendo la prueba, el ejemplo, y la excepción original. Si la salida no coincide, entonces se lanza una excepciónDocTestFailure
, conteniendo la prueba, el ejemplo, y la salida real.Para información sobre los parámetros de construcción y los métodos, véase la documentación para
DocTestRunner
en la sección API avanzada.
Hay dos excepciones que se pueden lanzar por instancias de DebugRunner
:
-
exception
doctest.
DocTestFailure
(test, example, got)¶ Una excepción lanzada por
DocTestRunner
para señalar que la salida real del ejemplo de un doctest no coincidió con su salida esperada. Los argumentos del constructor se usan para inicializar los atributos del mismo nombre.
DocTestFailure
define los siguientes atributos:
-
DocTestFailure.
got
¶ La salida real del ejemplo.
-
exception
doctest.
UnexpectedException
(test, example, exc_info)¶ Una excepción lanzada por
DocTestRunner
para señalar que un ejemplo de doctest lanzó una excepción inesperada. Los argumentos del constructor se usan para inicializar los atributos del mismo nombre.
UnexpectedException
define los siguientes atributos:
-
UnexpectedException.
exc_info
¶ Una tupla que contiene información sobre la excepción inesperada, como es retornado por
sys.exc_info()
.
Plataforma improvisada¶
Como se menciona en la introducción, doctest
ha crecido para tener tres usos primarios:
Verificar los ejemplos en los docstring.
Pruebas de regresión.
Documentación ejecutable / pruebas literarias.
Estos usos tienen diferentes requerimientos, y es importante distinguirlos. En particular, llenar tus docstring con casos de prueba desconocidos conduce a mala documentación.
Cuando se escribe un docstring, escoja ejemplos de docstring con cuidado. Hay un arte para eso que se debe aprender – puede no ser natural al comienzo. Los ejemplos deben añadir valor genuino a la documentación. Un buen ejemplo a menudo puede valer muchas palabras. Si se hace con cuidado, los ejemplos serán invaluables para tus usuarios, y compensarán el tiempo que toma recolectarlos varias veces mientras los años pasan y las cosas cambian. Todavía estoy sorprendido de qué tan frecuente uno de mis ejemplos de doctest
paran de funcionar después de un cambio «inofensivo».
Doctest también es una excelente herramienta para pruebas de regresión, especialmente si no escatimas en texto explicativo. Al intercalar prosa y ejemplos, se hace mucho más fácil mantener el seguimiento de lo que realmente se está probando, y por qué. Cuando una prueba falla, buena prosa puede hacer mucho más fácil comprender cuál es el problema, y cómo debe ser arreglado. Es verdad que puedes escribir comentarios extensos en pruebas basadas en código, pero pocos programadores lo hacen. Quizás es porque simplemente doctest hace escribir pruebas mucho más fácil que escribir código, mientras que escribir comentarios en código es mucho más difícil. Pienso que va más allá de eso: la actitud natural cuando se escribe una prueba basada en doctest es que quieres explicar los puntos finos de tu software, e ilustrarlos con ejemplos. Esto naturalmente lleva a archivos de pruebas que empiezan con las características más simples, y lógicamente progresan a complicaciones y casos extremos. Una narrativa coherente es el resultado, en vez de una colección de funciones aisladas que pruebas trozos aislados de funcionalidad aparentemente al azar. Es una actitud diferente, y produce resultados diferentes, difuminando la distinción entre probar y explicar.
Pruebas de regresión se limitan mejor a objetos o archivos dedicados. Hay varias opciones para organizar pruebas:
Escribe archivos de texto que contienen los casos de prueba como ejemplos interactivos, y prueba los archivos usando
testfile()
oDocFileSuite()
. Esto es lo recomendado, aunque es más fácil hacerlo para nuevos proyectos, diseñados desde el comienzo para usar doctest.Define funciones nombradas
_regrtest_topic
que consisten en docstrings únicas, que contienen casos de prueba por los tópicos nombrados. Estas funciones se pueden incluir en el mismo archivo que el módulo, o separadas en un archivo de prueba separado.Define un diccionario
__test__
que asigna desde temas de prueba de integración a los docstring que contienen casos de prueba.
Cuando has puesto tus pruebas en un módulo, el módulo puede ser el mismo test runner. Cuando una prueba falla, puedes hacer que tu test runner vuelva a ejecutar sólo los doctest fallidos mientras que tu depuras el problema. Aquí hay un ejemplo mínimo de tal test runner:
if __name__ == '__main__':
import doctest
flags = doctest.REPORT_NDIFF|doctest.FAIL_FAST
if len(sys.argv) > 1:
name = sys.argv[1]
if name in globals():
obj = globals()[name]
else:
obj = __test__[name]
doctest.run_docstring_examples(obj, globals(), name=name,
optionflags=flags)
else:
fail, total = doctest.testmod(optionflags=flags)
print("{} failures out of {} tests".format(fail, total))
Notas al pie de página
- 1
No se admiten los ejemplos que contienen una salida esperada y una excepción. Intentar adivinar dónde una termina y la otra empieza es muy propenso a errores, y da lugar a una prueba confusa.