jueves, 9 de junio de 2016

Test funcionales en Pyramid para vistas que requieren autenticación

Los test funcionales no están funcionando en este momento.
======================================================================
ERROR: test_ficheros_borrado (aplicacion.tests.testFuncionales.Borrado)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/var/www/ambiente/aplicacion/aplicacion/tests/testFuncionales.py", line 78, in setUp
    self.testapp.post_json('/ficheros', status=200, params=datos)
  File "/var/www/ambiente/local/lib/python2.7/site-packages/WebTest-2.0.21-py2.7.egg/webtest/utils.py", line 36, in wrapper
    return self._gen_request(method, url, **kw)
  File "/var/www/ambiente/local/lib/python2.7/site-packages/WebTest-2.0.21-py2.7.egg/webtest/app.py", line 740, in _gen_request
    expect_errors=expect_errors)
  File "/var/www/ambiente/local/lib/python2.7/site-packages/WebTest-2.0.21-py2.7.egg/webtest/app.py", line 636, in do_request
    self._check_status(status, res)
  File "/var/www/ambiente/local/lib/python2.7/site-packages/WebTest-2.0.21-py2.7.egg/webtest/app.py", line 671, in _check_status
    "Bad response: %s (not %s)", res_status, status)
AppError: Bad response: 403 Forbidden (not 200)

(...)
Como mencioné, estos ya suceden en un nivel bastante arriba de la aplicación, casi que son las peticiones tan normales como las que hacemos con el navegador.

Los test unitarios siguen testando partes específicas del código sin importarle en realidad la actitud HTTP, incluso aunque en unos de ellos usemos un pyramid.request.Request para la petición. Que es real, pero no tan real como se esperaría, y vemos que eso es un poco bueno.

Por otra parte, webtest.TestApp es tan real que de hecho acepta cookies. Ahora veremos lo conveniente de automatizar los test: Nos seguimos ahorrando hacer un intento de formulario con una simple petición post
self.testapp.post('/login', status=302, params={'username':'vtacius'})
Y algo tan simple en el setUp de cada clase nos permitirá autenticarnos en el sistema y realizar todas las operaciones que queramos comprobar
Así que autenticamos los test de la siguiente forma en el fichero correspondiente ./ambiente/aplicacion/aplicacion/tests/testFuncionales.py:
#coding:utf-8

from unittest import TestCase

class Listado(TestCase):
    def setUp(self):
        from aplicacion import main
        from webtest import TestApp
        
        app = main({})
        self.testapp = TestApp(app)
    
    def test_ficheros_listado(self):
        respuesta = self.testapp.get('/ficheros', status=200, xhr=True)
        self.assertEqual(respuesta.content_type, 'application/json')
        self.assertItemsEqual(respuesta.json_body['respuesta'], ['alortiz', 'kpenate', 'opineda']) 

class Detalle(TestCase):
    def setUp(self):
        from aplicacion import main
        from webtest import TestApp

        app = main({})
        self.testapp = TestApp(app)

    def test_unauth_detalle(self):
        respuesta = self.testapp.get('/ficheros/' + 'alortiz', status=403, xhr=True)
        self.assertRegexpMatches(respuesta.body, 'Access was denied to this resource')

    def test_ficheros_detalle(self):
        # Habrá que loguear en cada test si no se hace en setUp()
        self.testapp.post('/login', status=302, params={'username':'vtacius'})
        respuesta = self.testapp.get('/ficheros/' + 'alortiz', status=200, xhr=True)
        self.assertItemsEqual(respuesta.json_body['respuesta']['palabras'], ['ambiente', 'publico'])

    def test_ficheros_detalle_inexistente(self):
        # Habrá que loguear en cada test si no se hace en setUp()
        self.testapp.post('/login', status=302, params={'username':'vtacius'})
        respuesta = self.testapp.get('/ficheros/' + 'fitzcarraldo', status=200, xhr=True)
        self.assertEqual(respuesta.json_body['respuesta']['error'], 'No such file or directory')

class Creacion(TestCase):
    def setUp(self):
        from aplicacion import main
        from webtest import TestApp

        app = main({})
        self.testapp = TestApp(app)
        # Loguemos en la aplicación con datos reales
        self.testapp.post('/login', status=302, params={'username':'vtacius'})

    def tearDown(self):
        respuesta = self.testapp.delete('/ficheros/' + 'fcornejo', status=200)

    def test_ficheros_creacion(self):
        datos = {'usuario': 'fcornejo', 'data': {'nombre': 'Flor', 'apellido':'Cornejo', 'palabras': ['ente', 'obvio']}}
        respuesta = self.testapp.post_json('/ficheros', status=200, params=datos)
        self.assertDictEqual(respuesta.json_body['respuesta'], datos['data'])

class Modificacion(TestCase):
    def setUp(self):
        from aplicacion import main
        from webtest import TestApp

        app = main({})
        self.testapp = TestApp(app)
        # Loguemos en la aplicación con datos reales
        self.testapp.post('/login', status=302, params={'username':'vtacius'})

        datos = {'usuario': 'fcornejo', 'data': {'nombre': 'Flor', 'apellido':'Cornejo', 'palabras': ['ente', 'obvio']}}
        self.testapp.post_json('/ficheros', status=200, params=datos)
    
    def tearDown(self):
        respuesta = self.testapp.delete('/ficheros/' + 'fcornejo', status=200)
 
    def test_ficheros_modificacion(self):
        datos = {'usuario': 'fcornejo', 'data': {'nombre': 'Flor', 'apellido':'Cornejo', 'palabras': ['espejismo', 'olvido']}}
        respuesta = self.testapp.put_json('/ficheros/' + 'fcornejo', status=200, params=datos)
        self.assertDictEqual(respuesta.json_body['respuesta'], datos['data'])
       
class Borrado(TestCase):
    def setUp(self):
        from aplicacion import main
        from webtest import TestApp

        app = main({})
        self.testapp = TestApp(app)
        # Loguemos en la aplicación con datos reales
        self.testapp.post('/login', status=302, params={'username':'vtacius'})
        
        datos = {'usuario': 'fcornejo', 'data': {'nombre': 'Flor', 'apellido':'Cornejo', 'palabras': ['ente', 'obvio']}}
        self.testapp.post_json('/ficheros', status=200, params=datos)

    def test_ficheros_borrado(self):
        self.testapp.post('/login', status=302, params={'username':'vtacius'})
        
        respuesta = self.testapp.delete('/ficheros/' + 'fcornejo', status=200)

        self.assertEqual(respuesta.json_body['respuesta'], 'fcornejo')

Con un poco de verbosidad, la salida se verá ahora de la siguiente manera:
nosetests -v
test_ficheros_borrado (aplicacion.tests.testFuncionales.Borrado) ... ok
test_ficheros_creacion (aplicacion.tests.testFuncionales.Creacion) ... ok
test_ficheros_detalle (aplicacion.tests.testFuncionales.Detalle) ... ok
test_ficheros_detalle_inexistente (aplicacion.tests.testFuncionales.Detalle) ... ok
test_unauth_detalle (aplicacion.tests.testFuncionales.Detalle) ... ok
test_ficheros_listado (aplicacion.tests.testFuncionales.Listado) ... ok
test_ficheros_modificacion (aplicacion.tests.testFuncionales.Modificacion) ... ok
test_ficheros_borrado (aplicacion.tests.testUnitarios.Borrado) ... ok
test_ficheros_borrado_inexistente (aplicacion.tests.testUnitarios.Borrado) ... ok
test_ficheros_creacion (aplicacion.tests.testUnitarios.Creacion) ... ok
test_ficheros_creacion_json_malformed (aplicacion.tests.testUnitarios.Creacion) ... ok
test_ficheros_detalle (aplicacion.tests.testUnitarios.Detalle) ... ok
test_ficheros_detalle_noexistente (aplicacion.tests.testUnitarios.Detalle) ... ok
test_ficheros_listado (aplicacion.tests.testUnitarios.Listado) ... ok
test_ficheros_modificacion (aplicacion.tests.testUnitarios.Modificacion) ... ok

Name                                  Stmts   Miss  Cover   Missing
-------------------------------------------------------------------
aplicacion.py                            19      0   100%   
aplicacion/fichero_app.py                 0      0   100%   
aplicacion/fichero_app/ficheros.py       46     11    76%   21-22, 36, 52-55, 69-72
aplicacion/resources.py                   5      0   100%   
aplicacion/security.py                    5      0   100%   
aplicacion/tests.py                       0      0   100%   
aplicacion/tests/testFuncionales.py      69      0   100%   
aplicacion/tests/testUnitarios.py        99      0   100%   
aplicacion/views.py                       0      0   100%   
aplicacion/views/actividades.py          36      2    94%   48-49
aplicacion/views/autenticacion.py         7      0   100%   
-------------------------------------------------------------------
TOTAL                                   286     13    95%   
----------------------------------------------------------------------
Ran 15 tests in 1.546s

OK

No hay comentarios:

Publicar un comentario en la entrada

Otros apuntes interesantes

Otros apuntes interesantes