El framework symfony siempre ha sido empaquetado con un framework de pruebas funcionales y es, sin duda, una de sus principales fortalezas.
¿Qué es una prueba funcional? El objetivo de las pruebas funcionales es poner a prueba la integración de todas las capas de tu aplicación: desde el routing al controlador, plantillas, y las llamadas a la base de datos. Estas no reemplazan las pruebas unitarias.
La única cosa que no puede probar fácilmente es el código JavaScript embebido en tus plantillas. Por supuesto, puedes utilizar una herramienta como selenium para esto. Pero la buena noticia es que el framework de pruebas funcionales puede probar "algunos" códigos JavaScript como las llamadas Ajax.
Para hacer el trabajo, el framework de pruebas funcionales simula un navegador. No necesita un servidor web que conozca symfony y de como genera una respuesta basada en un peticion. Esto permite una fácil y profunda inspección del estado de tu aplicación después de cada solicitud. Puedes, por supuesto, inspeccionar los objetos del núcleo de symfony como la respuesta o la sesiones de usuario, pero también tu propio código al igual que el modelo.
(N. del T.: inspección = introspección )
Cada versión de symfony hace del framework de pruebas funcionales aun mejor. Hoy, les mostrare todos las bondades que agregamos a la versión symfony 1.2. Preparate para asombrarte!
Desconectando
Todo el mundo sabe que me gusta mucho testear. Tambien me gusta refactorear código viejo para hacerlo mejor. Para symfony 1.2, he refactoreado las clases del navegador (sfBrowser)
y del navegador de pruebas (sfTextBrowser) para hacerlas mas flexibles y configurables.
A partir de symfony 1.2, el framework de pruebas funcionales esta hecho de varias capas reusables e independientes.
El mayor cambio es la introducción de testers. Los Testers son objetos que saben como probar una capa específica de tu aplicación. Symfony viene hecho con testers para la petición, la respuesta, el usuario, el cache de la Vista, formularios, y Propel.
Un cambio menor es la introducción de sfTestFunctional class, la cual se basa en sfBrowser object para probar tu aplicación y manejar todos los testers registrados.
Aqui una típica prueba funcional:
$browser = new sfTestFunctional(new sfBrowser()); $browser-> get('/')-> // do some tests ;
Para mantener la compatibilidad para atras con symfony 1.0 y 1.1, aun puedes utilizar la ahora desestimada clase sfTestBrowser :
$browser = new sfTestBrowser(); $browser-> get('/')-> // do some tests ;
Testers
Entonces, todo el testing es en realidad hecho por las clases tester. Un tester sabe como probar una parte específica de tu aplicación.
Los testers remplazan todos los método que usabas, como checkResponseElement()
o isRequestParameter(). Por supuesto, estos métodos aun estan disponibles para mantener la compatibilidad hacia atrás (el archivo UPGRADE_TO_1_2
tiene una tabla que referencia todos los métodos viejos y sus tester equivalentes).
Aquí esta un ejemplo simple que demuestra como remplazar la llamada isRequestParameter() usando el tester:
// before symfony 1.2 $browser-> get('/')-> isRequestParameter('module', 'foo')-> checkResponseElement('h1', 'foo') ; // as of symfony 1.2 $browser-> get('/')-> with('request')->isParameter('module', 'foo')-> checkResponseElement('h1', 'foo') ;
El with('request') interrumpe el contexto del flujo de la interfaz para el objeto tester request para la próxima llamada. Entonces, el método isParameter() es un método sfTesterRequest.
También puedes crear un bloque de llamadas en el que el contexto es el Objeto tester:
$browser-> get('/')-> with('request')->begin()-> isParameter('module', 'foo')-> isParameter('action', 'index')-> end()-> checkResponseElement('h1', 'foo') ;
Todas las llamadas del método entre begin()y end() son llamadas contra el actual object tester.
Veamos los métodos de prueba provistos por las clases tester.
Request Tester
El request tester es definido en la clase sfTesterRequest y contiene los siguientes métodos:
| Método |
Descripción |
|---|---|
isParameter |
Prueba el parámetro request |
isMethod |
Prueba el método request |
isFormat |
Prueba el formato request |
hasCookie |
Prueba de si la petición ha dado una cookie |
isCookie |
Prueba el valor de una cookie |
$browser-> get('/')-> with('request')->begin()-> isParameter('module', 'foo')-> isMethod('get')-> isFormat('html')-> hasCookie('foo')-> isCookie('foo', 'bar')-> end() ;
Response Tester
El response tester es definido en la clase sfTesterResponse y contiene los siguientes métodos:
| Método | Descripción |
|---|---|
isStatusCode |
Prueba el código de estado del response |
contains |
Prueba el contenido del response con una simple expresión regular |
isHeader |
Prueba el valor de una cabecera dada |
checkElement |
Verifica el valor de un selector CSS3 |
$browser-> get('/')-> with('response')->begin()-> isStatusCode(200)-> contains('foo')-> isHeader('Content-Type', 'text/plain')-> checkElement('ul.foo li:last', '/foo/')-> end() ;
View cache tester
El view cache tester es definido en la clase sfTesterViewCache y contiene los siguientes métodos:
| Método | Descripción |
|---|---|
isCached |
Comprueba si una página/acción está en el caché |
isUriCached |
Comprueba si un determinado URI (puede ser un partial) está en el caché |
$browser-> get('/')-> with('view_cache')->begin()-> isCached(true)-> isUriCached('@sf_cache_partial?module=foo&action=_partial&sf_cache_key=some_cache_key')-> end() ;
User tester
El user tester es definido en la clase sfTesterUser y contiene los siguientes métodos:
| Método | Descripción |
|---|---|
isCulture |
Prueba la cultura del usuario |
isAuthenticated |
Comprueba que el usuario esta autenticado |
hasCredential |
Comprueba por una credencial de usuario |
isAttribute |
Prueba el valor de un determinado atributo |
isFlash |
Prueba el valor de una variable flash |
$browser-> get('/')-> with('user')->begin()-> isCulture('fr')-> isAuthenticated(true)-> hasCredential('admin')-> isAttribute('sfguard_user_id', '3')-> isFlash('notice', '/foo/')-> end() ;
Form Tester
Ha llegado la hora de descubrir algunos de los nuevos y sexy testers!
El form tester es definido en la clase sfTesterForm. Este sabe si un form se ha utilizado en la petición anterior, tiene una referencia al mismo objeto form, y te permite que inspeccionarlo.
| Método | Descripción |
|---|---|
hasErrors |
Compruebe si el formulario enviado tiene algún error |
isError |
Prueba el valor de un error para un campo determinado |
hasGlobalError |
Igual que isError pero para los errores globales |
El metodo isError() tiene el mismo tipo segundo argumento como el metodo
checkResponseElement().
$browser-> click('save', array(...))-> with('form')->begin()-> hasErrors()-> hasGlobalError('The login and password does not match.')-> isError('name', 'Required.')-> isError('name', '/Required/')-> isError('name', '!/Invalid/')-> isError('name')-> isError('name', false)-> isError('name', 1)-> end() ;
Propel Tester
Aquí esta otro gran tester: el propel tester.
No reemplaza las pruebas de la respuesta HTML pero es un medio para también comprobar las cosas que no se muestran en el navegador pero no por eso menos importante para testear
(por ejemplo si la fecha y hora del last_connection para un usuario ha sido actualizado,
o si el número de vistas para un artículo se ha incrementado, ...).
El propel tester es definido en sfTesterPropel en el Propel plugin y debe ser registrado antes de ser usado:
$browser->setTester('propel', 'sfTesterPropel');
Despues que el tester está registrado, puedes utilizarlo en tus pruebas:
$browser-> post('/')-> with('propel')->begin()-> check('Article', array('title' => 'foo'), false)-> check('Article', array('title' => '!foo'), false)-> check('Article', array(), 4)-> check('Article', array('title' => '%foo%'), true)-> check('Article', array('title' => '!%foo%'))-> check('Article', $criteria)-> end() ;
El propel tester sólo ofrece un método: check().Este método se comporta de manera diferente segun los argumentos que le pases a el:
- El primer argumento es el nombre de la clase del modelo
- El segundo es un objeto
Criteriao un simple array de las condiciones - El tercero puede ser:
truepara comprobar que algunos objetos coinciden con las condicionesfalsepara comprobar que ningun Objeto coincide con las condiciones- o un entero para comprobar el número de objetos coincidentes
Extender o crear un tester
El uso testers tiene varias ventajas:
- Aislamiento: Gracias a la desconexion de los testers, se proporcionan muchos más métodos de testing que antes.
- Legilibildad: Tus tests son mucho más legibles, gracias al concepto de bloque y nombres de métodos más cortos.
- Extensibilidad: Puedes ampliar cada tester con tus propios métodoso crear tu propia clase tester.
Extender un tester de la fabrica de symfony
Si deseas agregar algunos métodos para un tester existente, necesitas crear una clase que herede de un tester de fabrica y re-registrarlo con tu propio nombre de clase:
class ApplicationTesterRequest extends sfTesterRequest { // add some tester methods } // in your functional tests $browser->setTester('request', 'ApplicationTesterRequest');
Si necesita reemplazar un montón de testers de fabrica, puedes utilizar el metodo setTesters:
$browser->setTesters(array( 'request' => 'ApplicationTesterRequest', 'response' => 'ApplicationTesterResponse', ));
Un método tester puede hacer cualquier cosa que gustes pero siempre debe finalizar con el siguiente código para que el flujo de la interfaz funcione correctamente:
return $this->getObjectToReturn();
En tu método, tienes acceso a varios objetos:
$this->browser: El actual objeto browser$this->tester: El objetolime_test
Crear un nuevo tester
También se puede crear una nueva clase tester registrandola con un nombre único:
$browser->setTester('my_tester', 'myTester');
Una clase tester hereda de sfTester y debe implementar los métodos siguientes:
initialize(): Este método se llama cada vez que se está utilizandowith()en tus tests. Esto es útil para obtener algún objeto después de que la peticion se ha enviado:public function initialize() { $this->request = $this->browser->getRequest(); }
prepare(): Este método se llama justo antes de cualquier llamada al objeto browser. Esto es útil si necesitas hacer algo justo antes de que la peticion se envíe.
Se fluido
Cuando escribes un montón de tests funcionales para un determinado módulo, a veces es útil disponer de alguna información visual acerca de lo que se está haciendo. Los nuevos testers añade un nuevo nivel de indentación y hace tests mas legibles.
También, hay un nuevo método info() que produce algún texto para ayudar a categorizar tus tests:
$browser-> info('First scenario: Form with errors')-> // ... some tests info('Second scenario: Valid form submission')-> // ... some more tests ;

Depurando tests
Cuando un problema se produce en un test funcional, el HTML trasladado al navegador ayudar a diagnosticar la causa. A partir de symfony 1.2, esto es bastante fácil para mostrar el HTML generado sin interrumpir el estilo fluido de la interfaz:
$browser-> get('/a_uri_with_an_error')-> with('response')->debug()-> // some tests that won't be executed ;
El método debug() devolvera las cabeceras y el contenido e interrumpira el flujo del navegador.
El mismo método debug() existe para el form tester y devuelve los valores enviados y los errores del form si los hay:
$browser-> post('/post_to_a_form_with_some_errors')-> with('form')->debug()-> // some tests that won't be executed ;

Esto es todo por hoy. Nunca ha sido más fácil testear tus aplicaciones. Espero que el nuevo framework de testing pueda convencerte que no es dificil y que puede salvar tu día.
En cuanto a las nueva web debug toolbar, si creas nuevos testers, no dudes empaquetarlos como un plugin.
La presente, es una traducción al castellano realizada por Roberto G. Puentes Diaz, sobre el artículo new-in-symfony-1-2-test-your-applications de Fabien Potencier.
|
Este trabajo esta licenciado bajo una Licencia Creative Commons Atribución-No Comercial-Sin Obras Derivadas 3.0 Unported. |