viernes, 3 de junio de 2016

Automatizando las pruebas para Pyramid con Test Unitarios

Resulta que el test unitario es básicamente el doble del código que se pretende testar, pero así es la vida. El punto es que he supuesto algunas buenas prácticas que leía en alguna parte (O varias partes) y vergonzosamente he perdido los enlaces así que los incluyo luego.}
  • Cada test hace una sola cosa: Así que va un assert por cada método test_* 
  • Cada test es una unidad independiente: Lo que creo que tengo que revisar porque la duplicidad de código por ahora es un horror 
  • Los test no comparten fixtures: Pero es otra cosa que falta revisar porque sí 
  • Me apoyo en el uso de setUp y tearDown para inicializar/reinicializar el ambiente de cada test a valores conocidos
Creamos un paquete completo para los test unitarios, lo que es necesario sobre todo para ser capaces de invocar los demás paquetes de la aplicacion:
$ mkdir ./ambiente/aplicacion/aplicacion/tests/
$ touch ./ambiente/aplicacion/aplicacion/tests/__init__.py
$ ./ambiente/aplicacion/aplicacion/tests/testUnitarios.py
Por lo demás, el fichero ./ambiente/aplicacion/aplicacion/tests/testUnitarios.py queda de la siguiente forma:
#coding: utf-8 from unittest import TestCase

from unittest import TestCase
from pyramid import testing
from json import dumps

class Listado(TestCase):
    def setUp(self):
        self.config = testing.setUp()
    
    def tearDown(self):
        self.config = testing.tearDown()

    def test_ficheros_listado(self):
        from ..views.actividades import ficheros_listado
        peticion = testing.DummyRequest()
        respuesta = ficheros_listado(peticion)
        self.assertItemsEqual(respuesta['respuesta'], ['alortiz', 'kpenate', 'opineda'])

class Detalle(TestCase):
    def setUp(self):
        self.config = testing.setUp()

    def tearDown(self):
        self.config = testing.tearDown()
    
    def test_ficheros_detalle(self):
        from ..views.actividades import ficheros_detalle
        peticion = testing.DummyRequest()
        peticion.matchdict = {'usuario': 'alortiz'}
        respuesta = ficheros_detalle(peticion)
        self.assertItemsEqual(respuesta['respuesta']['palabras'], ['ambiente', 'publico'])

    def test_ficheros_detalle_noexistente(self):
        from ..views.actividades import ficheros_detalle
        peticion = testing.DummyRequest()
        peticion.matchdict = {'usuario': 'fitzcarraldo'}
        respuesta = ficheros_detalle(peticion)
        self.assertEqual(respuesta['respuesta']['error'], 'No such file or directory')

class Creacion(TestCase):
    def setUp(self):
        self.config = testing.setUp()

    def tearDown(self):
        self.config = testing.tearDown()
        from ..views.actividades import ficheros_borrado
        peticion = testing.DummyRequest()
        peticion.matchdict = {'usuario': 'fcornejo'}
        respuesta = ficheros_borrado(peticion)
    
    def test_ficheros_creacion (self):
        from ..views.actividades import ficheros_creacion
        from pyramid.request import Request
        contenido = dumps({'usuario': 'fcornejo', 'data': {'nombre': 'Flor', 'apellido':'Cornejo', 'palabras': ['ente', 'obvio']}})
        peticion = Request.blank('', {}, body = contenido)
        respuesta = ficheros_creacion(peticion)
        self.assertDictEqual(respuesta['respuesta'], {'nombre': 'Flor', 'apellido':'Cornejo', 'palabras': ['ente', 'obvio']})

    def test_ficheros_creacion_json_malformed(self):
        from ..views.actividades import ficheros_creacion
        from pyramid.request import Request
        contenido = "Esfuerzo mínimo para representar daño máximo"
        peticion = Request.blank('', {}, body = contenido)
        respuesta = ficheros_creacion(peticion)
        self.assertEqual(respuesta.status_code, 400)

class Modificacion(TestCase):
    def setUp(self):
        self.config = testing.setUp()
        from ..views.actividades import ficheros_creacion
        from pyramid.request import Request
        contenido = dumps({'usuario': 'fcornejo', 'data': {'nombre': 'Flor', 'apellido':'Cornejo', 'palabras': ['ente', 'obvio']}})
        peticion = Request.blank('', {}, body=contenido)
        respuesta = ficheros_creacion(peticion)
        self.assertDictEqual(respuesta['respuesta'], {'nombre': 'Flor', 'apellido':'Cornejo', 'palabras': ['ente', 'obvio']})
    
    def tearDown(self):
        self.config = testing.tearDown()
        from ..views.actividades import ficheros_borrado
        peticion = testing.DummyRequest()
        peticion.matchdict = {'usuario': 'fcornejo'}
        respuesta = ficheros_borrado(peticion)

    def test_ficheros_modificacion(self):
        from ..views.actividades import ficheros_modificacion
        from pyramid.request import Request
        contenido = dumps({'usuario': 'fcornejo', 'data': {'nombre': 'Flor', 'apellido':'Cornejo', 'palabras': ['especial', 'elemental']}})
        peticion = Request.blank('', {}, body=contenido)
        peticion.matchdict = {'usuario': 'fcornejo'}
        respuesta = ficheros_modificacion(peticion)
        self.assertDictEqual(respuesta['respuesta'], {'nombre': 'Flor', 'apellido':'Cornejo', 'palabras': ['especial', 'elemental']})
    
class Borrado(TestCase):
    def setUp(self):
        self.config = testing.setUp()
        from ..views.actividades import ficheros_creacion
        from pyramid.request import Request
        contenido = dumps({'usuario': 'fcornejo', 'data': {'nombre': 'Flor', 'apellido':'Cornejo', 'palabras': ['especial', 'elemental']}})
        peticion = Request.blank('', {}, body=contenido)
        respuesta = ficheros_creacion(peticion)
        self.assertDictEqual(respuesta['respuesta'], {'nombre': 'Flor', 'apellido':'Cornejo', 'palabras': ['especial', 'elemental']}) 
    
    def tearDown(self):
        self.config = testing.tearDown()

    def test_ficheros_borrado(self):
        from ..views.actividades import ficheros_borrado
        peticion = testing.DummyRequest()
        peticion.matchdict = {'usuario': 'fcornejo'}
        respuesta = ficheros_borrado(peticion)
        self.assertEqual(respuesta['respuesta'], 'fcornejo')
    
    def test_ficheros_borrado_inexistente(self):
        from ..views.actividades import ficheros_borrado
        peticion = testing.DummyRequest()
        peticion.matchdict = {'usuario': 'noexistente'}
        respuesta = ficheros_borrado(peticion)
        self.assertEqual(respuesta['respuesta']['error'], 'No such file or directory')

Al ser unidades separadas, cada test fallará por si mismo. Mi idea al inicio era la de crear, modificar y eliminar el mismo objeto. Pero resulta que eso no es tan buena idea como parece, para empezar porque los test, dentro de cada clase (E incluso las clases dentro de los paquetes) se ordenan por nombre al ejecutarse, lo que me daría nombres bien feos a todos los test. Pero por la misma idea de que cada test debe ser tan independiente como le sea posible

No hay comentarios:

Publicar un comentario en la entrada

Otros apuntes interesantes

Otros apuntes interesantes