Test-Driven Development
Publicado en Programación el 17 de September de 2009 por Manel Pérez MataTags: PHPUnit, Unit Test

Hace algún tiempo, os hablaba de la importancia de usar Unit Testing en nuestros desarrollos para tender localizados los posibles errores en cada una de nuestras funciones y, de ese modo, hacer un cambio en cualquier función no nos será crítico, ya que el test nos informará si la función está devolviendo los resultados esperados para cada cualquier.
Pero ¿y si al desarrollar el test me he dejado algún punto por comprobar? A menudo, tener una covertura del 100% resulta complicado debido al error humano, pero una vez detectado un error, debemos solventarlo y modificar el test para que no vuelva a darse ese error, y yendo un poco más allá, ¿por qué no pensar en los posibles errores que puede tener la función que desarrollemos antes de programarla? y ya que los hemos pensado, ¿por qué no realizar el test aunque todavía no hayamos desarrollado la función en questión? Pues precisamente, esa es la idea del Test-Driven Development (TDD a partir de ahora).
En resumen, podemos decir que el TDD es una práctica a la hora de programar que implica el desarrollo del test unitario antes de haber picado una sola línea del código de la función a testear… Pero, ¿qué ventajas tiene? ¿cuál es el workflow de esta práctica?
Ventajas de usar TDD
Generalmente, somos escépticos a la hora de adoptar una nueva práctica como el Unit Testing o más aún, algo que parece tan ilógico como TDD, pues es costoso en tiempo para el programador el desarrollo del test (cuando lo que nos gusta es desarrollar cosas útiles y no aparentemente inútiles como una prueba) e implica tener que pensar un rato antes de desarrollar. Sin embargo, seguir esta forma de programación tiene una serie de ventajas que hacen decantar la balanza a su favor:
- Código de mayor calidad: El hecho de desarrollar el test antes que la función a ser testeada, nos obliga a pensar en como será la función, ordenarla y ver que errores podrá haber. Esto hará que en el momento de empezar a picar la función, tengamos muy claro que es lo que queremos hacer y como, por tanto, el código será más limpio y concreto.
- Desacoplo del código: Cuando piensas en como será la función de manera que pueda ser testeada, te ves obligado a separar el bloque central en bloques más pequeños (que también serán testeados). De este modo, una función que podría ser muy compleja, acaba dividida en tres más pequeñas y fáciles de testear.
- Disminución del tiempo de desarrollo: Independientemente del coste en tiempo de desarrollar el test (pues doy por hecho de que estás convencido de su utilidad y lo desarrollarás igualmente), el desarollo de la función es más rápida porque ya hemos pensado que y como lo vamos a hacer, simplemente hay que picarlo.
- Disminución del número de líneas: TDD lleva implicita un proceso de refactorizando constante hasta que la función está acabada, gracias a eso, es fácil darnos cuenta que hemos complicado un proceso y lo podemos optimizar.
Workflow
Antes de comenzar el ciclo de trabajo se debe definir una lista de requerimientos. Luego se comienza el siguiente ciclo:
- Elegir un requerimiento: Se elige de una lista el requrimiento que se cree que nos dará mayor conocimiento del problema y que a la vez sea fácilmente implementable.
- Escribir una prueba: Se comienza escribiendo una prueba para el requerimiento. Para ello el programador debe entender claramente las especificaciones y los requisitos de la funcionalidad que está por implementar. Este paso fuerza al programador a tomar la perspectiva de un cliente considerando el código a través de sus interfaces.
- Verificar que la prueba falla: Si la prueba no falla es porque el requerimiento ya estaba implementado o porque la prueba es errónea.
- Escribir la implementación: Escribir el código más sencillo que haga que la prueba funcione. Se usa la metáfora “Déjelo simple” (”Keep It Simple, Stupid” (KISS)).
- Ejecutar las pruebas automatizadas: Verificar si todo el conjunto de pruebas funciona correctamente.
- Eliminación de duplicación: El paso final es la refactorización, que se utilizará principalemente para eliminar código duplicado. Se hacen de a una vez un pequeño cambio y luego se corren las pruebas hasta que funcionen.
- Actualización de la lista de requerimientos: Se actualiza la lista de requerimientos tachando el requerimiento implementado. Asimismo se agregan requerimientos que se hayan visto como necesarios durante este ciclo y se agregan requerimientos de diseño (P. ej que una funcionalidad esté desacoplada de otra).
Resumiendo en una imágen:















Leave a Reply