Pruebas unitarias (unit test) con python

Públicado en


Las pruebas unitarias o "unit test" por su término en inglés, son una herramienta muy poderosa en el desarrollo de software, las pruebas unitarias desde mi punto de vista, nos ayudan a evitar fuertes dolores de cabeza y desvelos imprevistos resolviendo problemas de ultimo minutos en la versión de producción.


Pero ¿de qué van las pruebas unitarias?, la respuesta es muy simple, consta en programar pequeñas pruebas que validen una función de nuestro programa, es decir, si tenemos un método llamado "divide_entre_dos" el cual recibe un número entero y te devuelve ese número dividido entre dos, nuestra prueba unitaria debería validar que en todo momento nuestro método devuelve el resultado esperado al ingresarle el valor correcto. Sé que este ejemplo es algo tonto, pero primero lo quiero explicar de la manera más simple posible. Veamos un mejor ejemplo.

Una buena práctica al desarrollar pruebas de cualquier tipo, no solo unitarias, es utilizar la metodología "test driven development" o "TDD", esta sugiere que para toda funcionalidad de la aplicación debemos escribir una prueba que valide el comportamientos de la misma, y debemos hacerlo antes de escribir el código de dicha funcionalidad, primero ver que la prueba no pase, si la prueba está bien hecha, esta debería pasar al escribir el código de la función a probar, y solo en ese caso.

Algo más o menos como esto:


# Primero escribiremos una clase vacía a probar
class Foo(object):
    pass

# Después el código de nuestra prueba
import unittest

class FooTestCase(unittest.TestCase):
# Instanciamos un objeto foo antes de correr cada prueba
    def setUp(self):
        self.foo = Foo()

    def test_get_gravatar_url(self):
        result = self.foo.gravatar_url("example1@gmail.com")
        self.assertEquals(result,
            "https://www.gravatar.com/avatar/f3e820cc128ffde207328176830dff87")

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

El código anterior es un ejemplo de cómo debería verse una prueba unitaria siguiendo la metodología TDD, primero escribo una clase "Foo" vacía, después hago una prueba para tratar de llamar el método "get_gravatar" de la clase y verificar su resultado.

Explicando algo mas del código escrito, debemos importar la librería "unittest" de python, y crear una clase que herede de "unittest.TestCase" para hacer las pruebas. Por estándar la clase "TestCase" cuenta con dos métodos auxiliares, "setUp" y "tearDown", estos métodos se ejecutan cada uno antes y después de correr cada método de prueba de la clase, por lo que debemos tomar en cuenta que cada prueba corre bajo un único contexto. Como última nota sólo agrego que no es obligatorio declarar setUp o tearDown, solo se usan en caso de ser necesario.

Para este ejemplo primero creo la instancia del objeto foo dentro de setUp, así me aseguro que cada prueba tendrá una instancia nueva de foo, y que cada una usa valores limpios al ejecutarse, este comportamiento de las pruebas unitarias es muy importante para evitar arrojar falsos positivos en los resultados. Por último, en una prueba unitaria todo método dentro de la clase prueba cuyo nombre inicie con "test_" será considerado como una prueba, y se ejecutará como una, por lo que las pruebas son básicamente estos métodos.

En cada prueba, se necesita un método "assert", ellos se encargaran de hacer las debidas validaciones para cada caso, y existen muchos tipos de asserts, en la documentación oficial de la librería unittest podemos ver mas a detalles cuantos existen y para qué sirven todos ellos, en el ejemplo solo necesité "self.assertEquals", que sirve para comparar dos valores y ver que sean iguales, de lo contrario, este lanzaría un error y la prueba no pasaría.

Hasta este punto es evidente que la prueba no pasará, principalmente por que el método "gravatar_url" no existe en la clase Foo.

Para que nuestra la pase solo basta modificar la clase Foo más o menos así:

import hashlib
class Foo(object):
    def gravatar_url(self, email):
        hash = hashlib.md5(email.lower()).hexdigest()
        return "https://www.gravatar.com/avatar/" + hash

Así de simple, el test pasará sin problemas.

Para concluir solo basta decir que la idea de las pruebas unitarias no se limita a validar cada componente de una aplicación por separado, también nos ayuda a definir cuál será el comportamiento deseado de ese componente, eso es una gran ayuda cuando no estás seguro de cómo resolver algo, pues las pruebas te exigen que definas lo que quieres para poder hacerla. En lo personal yo no me atrevería a desarrollar un proyecto grande sin tener pruebas unitarias, me gusta estar seguro que mientras trabajo en alguna función no rompí algo sin darme cuenta, y lo más importante, que no me llamaran a las tres de la mañana para decirme que la aplicación no funciona.

Por último dejo el link de la documentación oficial de la librería unittest de python, en mi proximo post hablare de mas herramientas para complementar el desarrollo de pruebas.

https://docs.python.org/2/library/unittest.html



Jesus Armando Anaya
Jesus Armando Anaya

Soy programador por profesión y por afición, me gusta estar aprendiendo, participar en comunidades, y buscar excusas para viajar lejos.


blog comments powered by Disqus