Cada vez que voy a una reunión de programadores Rails suelo preguntar para ver cuántos están empleando testing automatizado en sus aplicaciones, y aunque cada vez lo va usando más gente, en la actualidad no llega a 1/3 del total el número de programadores que los ha incorporado como práctica habitual en sus desarrollos.
El desarrollo guiado por tests (TDD, Test Driven Development) es una técnica de desarrollo de software mediante la cual trabajamos en iteraciones cortas cubiertas por tests automáticos que cubren la nueva funcionalidad que queremos en nuestra aplicación. Lo interesante del tema es que primero escribimos el test y después programamos la funcionalidad, hasta que el test pase con éxito. Cuando no se nos ocurren más casos en los que los tests fallen, hemos acabado con la programación.
Un ejemplo muy sencillo: supongamos que estamos programando un comercio electrónico y queremos que el modelo Producto tenga un método precio_con_iva que nos devuelva… el precio con IVA. Lo podemos comprobar con un test unitario como el siguiente:
def test_precio_con_iva @producto = Producto.new(:precio_base => 100) assert_equal 116, @producto.precio_con_iva end
Los tests consisten básicamente en eso… líneas tipo “assert…” que comprueban cosas. En este caso, que el precio con iva del producto recién creado cuyo precio base es 100, es igual (equal) a 116.
Creado el test, si lo pasamos fallará porque no existe ese método… lo siguiente sería definirlo en el modelo, y si lo hacemos bien (y devuelve 116 en este caso), pasará el test. Ya tendremos entonces la nueva funcionalidad programada, y un test más en nuestro saco que nos alertará en caso de que más adelante esa funcionalidad no funcione como esperamos.
Evidentemente, deberíamos escribir más casos de prueba, con distintos escenarios: productos sin precio, productos con otro tipo de IVA, etc., etc. Recordemos: cuando no se nos ocurren más casos de prueba que fallen, hemos terminado de programar.
Mediante los tests podemos comprobar muchos tipos de condiciones: comparar valores de campos, contar el total de registros de un modelo para ver si hay diferencia (antes / después) de una acción, verificar si es nil… pero incluso podemos testear los controladores para ver el tipo de respuesta (ok, redirect, etc.) e incluso el HTML generado por las vistas para verificar que existe determinada tag, etc., etc.
Otro aspecto interesante es intentar seguir la ley del mínimo esfuerzo, que es una de las cosas que nos enseña nuestra madre Naturaleza (las rocas ruedan cuesta abajo, no cuesta arriba) y una vez se rompen los tests, programar lo mínimo que necesitemos para que todo vuelva a funcionar. Primero, haz que vuelva a funcionar. Después, si quieres ya te podrás entretener en refactorizar tu código para que esté más optimizado. Si se te ocurren nuevos casos, recuerda primero escribir el test y después programar.
Entre las muchas ventajas de Ruby on Rails hay que destacar que viene muy bien preparado para crear los tests: conforme vamos creando modelos y controladores, se van creando los tests correspondientes dentro de la carpeta test… Echa un vistazo ahí dentro y verás algunas cosas:
- Fixtures. Para tus datos de prueba. Ahí definirás unos pocos datos de prueba para realizar los tests.
- Unit. Los tests unitarios, que prueban la funcionalidad de los modelos.
- Functional. Los tests funcionales, para testear controladores.
- Integration. Para los tests de integración, con lo que puedes simular una sesión de usuario que se pasea por varios controladores y cómo se relacionan unos con otros.
- Mocks. Nos permite simular el funcionamiento de otras partes de la aplicación, normalmente para conseguir una respuesta más rápida y controlada. Por ejemplo en mi aplicación Pagerankalert.com la uso para comprobar el PageRank que me devuelve Google… en lugar de consultar directamente a Google, en algunos de mis tests establezco el PR esperado. Así puedo testear incluso si no tengo conexión a Internet pq estoy trabajando en modo offline.
Desde nuestra aplicación Rails podemos ejecutar tests puntuales, o toda la batería de tests… y mediante la utilidad autotest que proporciona la gema ZenTest, podemos tener un demonio que estará vigilando constantemente nuestra aplicación en desarrollo. Cada vez que modifiquemos un archivo, ejecutará los tests asociados a él para comprobar si nuestros cambios han hecho que deje de funcionar algún test. En ese caso nos informará del error, y una vez que lo corrijamos volverá a pasar toda la batería de tests completa y seguirá vigilando nuestros pasos.
Por último, mencionar otras herramientas de test externas a Rails pero también muy interesantes y necesarias:
- Watir / Firewatir. Permite testear desde dentro del navegador, esto es, lanzar una instancia del navegador mediante un script, rellenar campos, pulsar botones, enviar formularios y comprobar los textos de la página. Interesante para poder probar eventos Javascript, AJAX…
- Mechanize. Simula navegación por páginas desde consola, mediante scripts de Ruby podemos indicar que visite tal página, rellene formularios, los envíe, pulse enlaces, compruebe textos… Es interesante pq una de las limitaciones de Watir es que sólo puede abrir un navegador a la vez; mientras que con mechanize puedes lanzar el mismo script en paralelo y por ejemplo simular 50 usuarios subiendo fotos a una aplicación…
En resumen, para mí la diferencia fundamental entre seguir el desarrollo guiado por tests y no hacerlo es la paz mental que consigues, la confianza en la calidad de tu programación. Cuando ves que se han ejecutado 500, 1000… tests y todos han ido bien, sientes que lo tienes todo bajo control.
Cuando algo falla, si antes de corregirlo lo cubres con un test, ya sabes que para la siguiente ocasión eso no fallará. Y cuando tocas un código en un sitio y eso hace que falle en otro que no recordabas que estaba relacionado, das las gracias al TDD por haberte avisado de algo que no se te había ocurrido que podía fallar.
¡Animate y pásate al TDD!
5 comments ↓
Buen artículo
Muy buen resumen de los test. Claro y conciso.
Yo soy uno de esos 2/3 de programadores restantes que cada inicio de año se pone como buen propósito escribir tests en sus aplicaciones, pero que al acabar el año sigue como buen propósito
Aunque cuando empieze, creo que empezaré con BDD (Behaviour Driven Development) que por lo que he leido me parece que tiene más ventajas (a la vez que testeas te obliga a pensar especificaciones de tu aplicación, test más intuitivos de leer, etc…).
¿tienes (o alguno de los lectores) experiencia con BDD?, ¿alguien que haya probado las dos (TDD-BDD) puede dar su visión de estas técnicas?.
Un buen consejo, ojalá hiciésemos más uso de los test en nuestros proyectos.
Me apunto los links.
Buenas Jaime, llevo unos días liado con el tema de los tests pero no termino de aclararme con ellos, a bote pronto las dudas que se me plantean son las siguientes.
Yo uso rspec (o lo intento) y todos los tests que he creado están ahí, no se si también he de crear los test de las carpeta “/tests”.
Una vez teniendo aclarado eso, mi problema es el de encontrar código de ejemplo en el que fijarme, pues todos los que encuentro se refieren a a esta última carpeta que te comento (unitarios, funcionales…) y dejando de lado los de spec (modelos, controladores…)
Gracias por adelantado, también aprovecho para decir que seguro que no soy el único que agradecería un tutorial sobre el asunto, al estilo de “Rolling with rails” pero centrado en tests.
Ya no pido más que me voy para clase
Hola ceritium, con rspec todavía no puedo ayudarte, pq yo no uso (todavía rspec…)… pero sí que me gustaría hacer próximamente más tutoriales cortos sobre testing en rails.
Leave a Comment