0% encontró este documento útil (0 votos)
34 vistas

Python Tema7 Parte4 Unittest v1

Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
34 vistas

Python Tema7 Parte4 Unittest v1

Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 15

IBM SkillsBuild | Introducción a Python

Pruebas con Python


Unittest

1
IBM SkillsBuild | Introducción a Python

Índice
Introducción 3
Un proceso de automatización de verificación 4
Ejemplos de uso 7
Testing con excepciones 9
Verificación de tipos 11
Buenas prácticas en testing unitario 14
Códigos usados en los ejemplos 14

2
IBM SkillsBuild | Introducción a Python

Introducción

Existen numerosas librerías para unit testing.


Posiblemente unittest es el estándar para pruebas de
testing. Es el marco de prueba más extendido y
además ya viene incorporado en el propio Python.
Para usarlo no hay más que importarlo.

3
IBM SkillsBuild | Introducción a Python

Un proceso de valores = [1, 3, 0, -1, -3, 2+3j, True,

automatización de 'hola']

verificación
Viendo el comportamiento de la función al pasarle los
parámetros sabremos si la función está trabajando
Con unittest vamos a hacer un proceso de
correctamente, aunque nosotros le estemos pasando
automatización de la verificación de nuestro código.
valores erróneos.

Por ejemplo, partimos de la siguiente función para


Es una forma de poder conocer con qué valores va a
calcular un área:
funcionar correctamente mi función y con cuáles no.

from math import pi

def area(r):
areaC = pi*(r**2)
return areaC Recorremos nuestra función pasándole los
parámetros de nuestra lista:

Sabemos que a esta función no podemos darle


determinados valores, como por ejemplo valores for v in valores:
negativos, strings o booleans. areaCalculada = area(v)
print('Para el valor', v, 'el área
Vamos a hacer una prueba, de momento sin usar es', areaCalculada)
unittest. Vamos a crear una lista con una serie de
valores que vamos a pasar como parámetro y vamos
a ver el comportamiento que tiene esa función con
esos valores.

4
IBM SkillsBuild | Introducción a Python

Y obtenemos el siguiente resultado:

Vemos que:

- Para los valores 1, 3 y 0 nos da resultados


correctos
- Para -1 y -3 nos da valores que no son lo que
debería dar, por lo que ya sabemos que,
cuando ingresemos radios negativos,
tendremos que hacer algo al respecto, como
por ejemplo lanzar una excepción.
- Para el número complejo (2+3j) el resultado
tampoco es lo esperado.
- Para el valor True el resultado tampoco es lo
esperado.
- Para el valor ‘hola’ directamente obtenemos
un error de tipo.

5
IBM SkillsBuild | Introducción a Python

Ya sabemos que nuestra función está bien realizada, Entonces, debemos nombrar nuestros archivos de
hace su trabajo, pero dependiendo de los valores que prueba con la palabra clave test en el arranque.
le pasemos, puede dar problemas. Hace cálculos que
Importamos unittest:
no se deberían llevar a cabo e incluso da error
cuando le pasamos una cadena de texto.

import unittest
Este es un test muy primitivo. Haciendo uso de
unittest podemos automatizar el proceso de prueba
de nuestro código.
Importamos la función sobre la cual se van a ejecutar
Para usar unittest tenemos que seguir un protocolo,
los test:
vamos a tener que crear otro archivo en el que se va
a encontrar el propio código de unittest.
from testing01 import area
Deberemos crear un archivo con el siguiente nombre:

test_nombreArchivo.py
Y en nuestro caso tendremos que importar también
El nombre deberá empezar por la palabra test_
PI:
seguido del nombre del archivo sobre el que vamos a
realizar las pruebas. De tal forma que, si nuestro
archivo se llama, por ejemplo, funcionRadio.py, el from math import pi
archivo de testing se debería llamar
test_funcionRadio.py.

En nuestro caso el archivo a probar se va a llamar Lo siguiente será crear una clase que herede de la
testing01.py y el archivo de pruebas clase TestCase:
test_testing01.py

Para ejecutarlo, pondremos en la consola: class TestArea(unittest.TestCase):

python -m unittest test_testing01.py


En esta clase es donde vamos a poner nuestros test.

Vamos a crear al primero. Lo que haremos es crear


Donde test_testing01.py será el nombre de mi un método cuyo nombre debe empezar por la palabra
archivo de pruebas. test.

Nota: Podemos ejecutar automáticamente las Ahora, dependiendo del tipo de test que queramos
pruebas usando el comando: hacer, deberemos invocar un método de la clase
TestCase. Los más usados son:
python -m unittest discover
assertTrue() o assertFalse() para verificar una
Con esta sintaxis no necesitamos mencionar el condición.
nombre de archivo de la prueba. Unittest encontrará
las pruebas utilizando la convención de
nomenclatura que seguimos.

6
IBM SkillsBuild | Introducción a Python

assertRaises() para asegurar que se lanza una


excepción específica. Se utilizan estos métodos en import unittest
lugar de la sentencia assert para que el ejecutor de from testing01 import area
pruebas pueda acumular todos los resultados de la from math import pi
prueba de cara a realizar un informe.
class TestArea(unittest.TestCase):
Los métodos setUp() y tearDown() permiten definir def test_area(self):
instrucciones que han de ser ejecutadas antes y print('-----Test valores de
después, respectivamente, de cada método de resultado conocido-----')
prueba.
self.assertAlmostEqual(area(1),
pi)
assertAlmostEqual() para comprobar si el resultado self.assertAlmostEqual(area(0),
de una prueba es exactamente igual a un dato que 0)
conocemos, por ejemplo una variable en concreto. self.assertAlmostEqual(area(3),
pi*(3**2))
El quid de cada test es la llamada
a assertEqual() para verificar un resultado esperado.

Recordemos que tenemos que ejecutar nuestro test


Ejemplos de uso poniendo en la consola:

python -m unittest test_testing01.py


Veamos ejemplos de uso de alguno de estos
métodos.

El primer test que vamos a crear es para saber si


nuestra función ha generado un valor que sabemos
que es correcto. Vamos a meter un valor conocido y
No nos indica ningún fallo, por lo que podemos decir
ver si el resultado corresponde a lo que sabemos que
que las pruebas fueron positivas. Es decir, todos los
debería dar.
resultados reales son iguales a los esperados.
Para ello debemos invocar al método
Vamos a ejecutar de nuevo, pero forzando a que se
assertAlmostEqual() pasando como primer
produzca un fallo para ver la diferencia. En la línea 10
parámetro nuestra función con el parámetro de
de nuestro programa hemos cambiado el valor
entrada y como segundo parámetro el resultado que
esperado de 0 por un 1, que sabemos que no sería
sabemos que debe dar.
correcto.

7
IBM SkillsBuild | Introducción a Python

Ejecutamos de nuevo con:

python -m unittest test_testing01.py

Y el resultado:

Vemos que nos da un fallo en la línea 10. Era lo


esperado.

8
IBM SkillsBuild | Introducción a Python

Testing con excepciones


Para ello tendremos que usar el método assertRaises
al que hay que pasarle tres parámetros; el tipo de
excepción, la función a comprobar y el valor de salida
esperado:
Uno de los problemas que tenemos con funciones
que reciben valores numéricos es que los valores
#Test de valores negativos
introducidos no se encuentran en el rango adecuado. def test_negativos(self):
Por ejemplo, en nuestra función el rango de valores print('-----Test de valores
negativos no es factible. negativos-----')

Si ya sabemos que nuestra función no va a sacar


#Indicamos el tipo de excepción,
valores coherentes si los parámetros de entrada son la función y el valor esperado.
negativos, lo que tenemos que hacer es crear una self.assertRaises(ValueError,
excepción que de lance en dichos casos. area, -1)

En unittest no solo tenemos que comprobar que la


función nos devuelva los resultados correctos,
también tenemos que asegurarnos de que se Al ejecutar el código con python -m unittest
disparan las excepciones correctamente según los test_testing01.py
casos.
Nos muestra el siguiente mensaje:
Ejemplo:

En nuestro archivo testing01.py modificamos la


función a comprobar añadiéndole una excepción:

def area(r): Como vemos, no nos saca ningún mensaje de error,


if r<0: lo que significa que la excepción se ha lanzado
raise ValueError("No se permiten correctamente.
valores negativos")
areaC = pi*(r**2) Vamos a ver qué hubiese pasado si no tenemso
return areaC prevista la excepción en nuestro código.

Modificamos nuestra función, comentamos la línea


de la excepción y la sustituimos simplemente por un
Hemos creado la misma función, pero le hemos
print():
añadido una excepción que se disparará en el caso
de encontrar parámetros de entrada negativos. Para
el resto de valores la función se ejecuta como antes. def area(r):
if r<0:
En nuestro archivo test_testing01.py creamos una #raise ValueError("No se permiten
nueva función que compruebe la correcta ejecución valores negativos")
en caso de valores de entrada negativos. print("No se permiten valores
negativos")
areaC = pi*(r**2)
return areaC

9
IBM SkillsBuild | Introducción a Python

Ejecutamos el test:

Vemos que en esta ocasión nos da un fallo ya que no


hemos hecho un tratamiento correcto de la
excepción.

Por lo tanto ya hemos visto como con assertRaises()


comprobamos que la función está ejecutando la
excepción adecuada en el caso de que pasemos un
parámetros que no sea válido.

10
IBM SkillsBuild | Introducción a Python

Verificación de tipos

Vamos a ver ahora cómo comprobar si el tipo de


datos que está recibiendo la función mediante
parámetro es correcto o no.

Para este tipo de test vamos a usar nuevamente el


método assertRaises() y el tipo de excepción que
estamos esperando que se lance es de tipo
TypeError.

Creamos una prueba para cada tipo de dato que


sabemos con certeza que no nos va a valer en
nuestra función:

# Test de tipos no compatibles.


# Verificamos si el tipo de los
parámetros es el correcto.
# El tipo de la excepción debe
ser TypeError
# Hacemos una prueba para que
cada tipo conocido no válido

def test_tipos(self):
print('-----Test de tipos no
compatibles-----')
self.assertRaises(TypeError,
area, True)
self.assertRaises(TypeError,
area, 'hola')
self.assertRaises(TypeError,
area, 2+3j)

Si nuestra función lanza una excepción al recibir este


tipo de datos, nuestro test no nos dará ningún error.
Si la función no lanza una excepción, entonces el test
sí nos dará errores.

11
IBM SkillsBuild | Introducción a Python

El resultado:

12
IBM SkillsBuild | Introducción a Python

Vemos que nuestro test ha lanzado errores. En


concreto se queja de que la ejecución
correspondiente a la línea 37 ha fallado. Es decir, que
nuestra función no lanza errores si el tipo de dato
recibido es un boolean.

Ya tenemos información de los cambios que


debemos hacer en nuestra función area.

Vamos a crear una nueva excepción que trate los


casos en los que el parámetro de entrada no sea un
número entero o de coma flotante:

#Función con la excepción TypeError y


verificación de negativos

def area(r):

#Verificamos los tipos correctos


if type(r) not in [float, int]:
raise TypeError("Solo números
enteros o de coma flotante.")

#Verificamos los valores negativos


if r<0:
raise ValueError("No se permiten
valores negativos")

areaC = pi*(r**2)
return areaC

Si lanzamos nuestro test ahora:

13
IBM SkillsBuild | Introducción a Python

Ahora sí tenemos el test sin fallos. Lo que significa • Las pruebas deben producir mensajes
que ya tenemos tratados los casos en los que los significativos cuando fallan. Intenta hacer que la
valores de entrada no sean números enteros prueba falle y ver si el motivo del fallo se puede
positivos o números de coma flotante positivos. determinar leyendo el resultado del caso de
prueba.
Como podemos ver los unittest son una herramienta

Códigos usados en los


sencilla y poderosa con la que poder automatizar el
proceso de testing de nuestro código. Comprobando
los valores que conocemos con certeza que son
válidos, los que conocemos con certeza que no lo son
ejemplos
y las excepciones de nuestro código.
Nuestros códigos finalmente deberían haber
A continuación se expone un decálogo de buenas
quedado de la siguiente forma.
prácticas a la hora de crear pruebas unitarias.
Archivo testing01.py:
Buenas prácticas en from math import pi
testing unitario def area(r):

• Las pruebas deben ser pequeñas y probar solo #Verificamos los tipos correctos
if type(r) not in [float, int]:
una cosa.
raise TypeError("Solo números
• Las pruebas deben ejecutarse rápido. Esto es
enteros o de coma flotante.")
esencial para la inclusión en un entorno de CI.
• Las pruebas unitarias deben ser completamente if r<0:
independientes. Las pruebas no deben depender raise ValueError("No se permiten
unas de otras y pueden ejecutarse en cualquier valores negativos")
orden cualquier número de veces.
• Las pruebas deben estar completamente areaC = pi*(r**2)
automatizadas y no requerir interacción manual o return areaC
verificaciones para determinar si pasan o fallan.
• Las pruebas no deben incluir afirmaciones
innecesarias como "puntos de control" en la
prueba. Afirma solo lo que la prueba está
probando.
• Las pruebas deben ser portátiles y ejecutarse
fácilmente en diferentes entornos.
• Las pruebas deben configurar lo que necesitan
para ejecutarse. Las pruebas no deben hacer
suposiciones sobre recursos particulares
existentes.
• Las pruebas deben limpiar los recursos creados
después.
• Los nombres de las pruebas deben describir
claramente lo que están probando.

14
IBM SkillsBuild | Introducción a Python

Archivo test_testing01.py:

import unittest
from testing01 import area
from math import pi

class TestArea(unittest.TestCase):

def test_area(self):
print('-----Test valores de
resultado conocido-----')
self.assertAlmostEqual(area(1),
pi)
self.assertAlmostEqual(area(0), -
1)
self.assertAlmostEqual(area(3),
pi*(3**2))

#Test de valores negativos


def test_negativos(self):
print('-----Test de valores
negativos-----')

#Indicamos el tipo de excepción,


la función y el valor esperado.
self.assertRaises(ValueError,
area, -1)

# Test de tipos no compatibles.


Verificamos si el tipo de los parámetros
es el correcto.
# El tipo de la excepción debe
ser TypeError
# Hacemos una pueba para que cada
tipo conocido no válido

def test_tipos(self):
print('-----Test de tipos no
compatibles-----')
self.assertRaises(TypeError,
area, True)
self.assertRaises(TypeError,
area, 'hola')
self.assertRaises(TypeError,
area, 2+3j)

15

También podría gustarte