Contenido

Python: Cómo hacer pruebas 1: doctest

Voy a redactar distintas maneras de hacer pruebas en Python. En este sentido, veremos diferentes estilos, desde el más sencillo al más complejo; desde las pruebas unitarias hasta las pruebas de sistema.

Estoy convencido de que me voy a dejar mil historias en el tintero… os ruego un poco de paciencia y de ayuda :D

En esta primera entrega, veremos cómo probar utilizando los desconocidos doctest.

Python

Función de ejemplo

Vamos a practicar con la función que obtiene el factorial de un número, función que queremos probar. Es decir, que tenemos la función:

1
2
def factorial(n):
    return 1 if n < 1 else n * factorial(n-1)

Y queremos probar si funciona.

Pruebas en la documentación

Por esta razón vamos a añadirle el paquete doctest y la línea de ejecución adecuada:

1
2
3
4
5
6
7
import doctest

def factorial(n):
    return 1 if n < 1 else n * factorial(n-1)

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

Finalmente, será necesario añadir un comentario a la función, de la misma manera que lo veríamos en el intérprete en línea:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import doctest

def factorial(n):
    """
    >>> factorial(3)
    6
    >>> factorial(4)
    24
    >>> factorial(5)
    120
    """
    return 1 if n < 1 else n * factorial(n-1)


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

Ejecutando, que es gerundio

Vamos a ver lo que ocurre cuando lo ejecutamos. Por favor, hacedlo.

¿Nada? Eso es porque todo ha ido bien. Pero claro, no podemos fiarnos… Así que ejecutaremos de nuevo pero con el parámetro -v:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ ./example1.py -v
Trying:
    factorial(3)
Expecting:
    6
ok
Trying:
    factorial(4)
Expecting:
    24
ok
Trying:
    factorial(5)
Expecting:
    120
ok
1 items had no tests:
    __main__
1 items passed all tests:
   3 tests in __main__.factorial
3 tests in 2 items.
3 passed and 0 failed.
Test passed.
$

Madre mía, qué cosa más sencilla.

Separación de tests y pruebas

Usar este tipo de pruebas puede resultar un problema, ya que ensucia muchísimo el código. La solución está en sacarlo a un archivo diferente. De esta manera, el código se quedará más limpio (ojo a la función doctest.testfile):

1
2
3
4
5
6
7
import doctest

def factorial(n):
    return 1 if n < 1 else n * factorial(n-1)

if __name__ == "__main__":
    doctest.testfile('example2.txt')

Separando los tests a un fichero externo, que en este caso se tiene que llamar example2.txt:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
Módulo de ejemplo
=================

Usando 'factorial'
------------------

Primero importamos nuestra función:

    >>> from example import factorial

Y esto es un ejemplo de lo bien que se nos da calcular factoriales:

    >>> factorial(3)
    6
    >>> factorial(4)
    24
    >>> factorial(5)
    120

Lo más divertido de este método es que podemos dejar perfectamente documentado nuestro código y que estos comentarios se van a probar. Es decir: si nuestro código cambia, invalidará la documentación.

El próximo día… UnitTest/UnitTest2

Para saber más…

Aunque pensaba utilizar la función del factorial, resulta que la misma idea la tuvieron ya la gente de Python al hacer el propio manual de doctest. Aún así os contarán muchas cosas que yo me he dejado en el tintero, como la captura de excepciones, etc.

También podéis preguntar en este foro y así responderemos a las preguntas entre todos