Cuando el Manifiesto por el Desarrollo Ágil vio la luz en 2001, tenía un foco muy claro en el desarrollo de software y de todo lo que lo rodeaba. Sin embargo, varios años atrás, los firmantes del manifiesto ya habían inventado técnicas como eXtreme Programming (XP), Scrum o Test-Driven Development (TDD). TDD es una técnica que plantea un paradigma diferente de cómo desarrollar software. No sólo pone de manifiesto la importancia de contar con test, sino que propone claramente que el desarrollo esté orientado a test. Explicamos esta técnica con algunos puntos claves, extraídos del libro Test-Driven Development de Kent Beck.
¡Tus test no pueden esperar!
Llevo muchos años participando en multitud de equipos tanto de proyecto como de producto. Muy pocos tenían test y casi ninguno hacía algo parecido a TDD. Una de las frases que me ha llamado la atención de Beck es: “Debemos escribir nuestros propios tests, no podemos esperar 20 minutos cada día para que otra persona lo haga”. Esta idea es clave, crear los test es parte del desarrollo de software. Esto choca con la filosofía de muchas empresas de tener figuras de QA que absorben esta responsabilidad.

El Ciclo de Trabajo en TDD
El ciclo habitual de TDD sigue los siguientes pasos:
- Escribe el test. Traduce la operación que tienes en la cabeza en código, estás escribiendo una historia. Añade a tu historia todos los elementos que consideres imprescindibles.
- Haz que funcione. Rápidamente, consigue que el test esté en verde, es decir que funcione. Busca soluciones simples que arreglen el problema. Si aparecen otros problemas, anótalos en una lista y céntrate en el problema principal. No importa que no sea la solución perfecta.
- Hazlo bien. Ahora, el código funciona, pero sabemos que lo hicimos rápidamente. Mejora tu código y mantenlo en verde.
El segundo punto es clave porque existe la refactorización posterior. Beck propone varias estrategias: usar constantes e irlas sustituyendo por variables que, de verdad, resuelvan las casuísticas o bien resolver si la implementación es trivial. Lo importante es que lo antes posible el test sea verde y, después, mejorar el código ¡Y no olvidemos el clean code!
¿Por qué usar Test?
Un test es una evolución, hay que ser muy osado para lanzar un software sin pruebas o estar muy seguros de nosotros mismos. Aunque podemos “probar” nuestro código, probar no es lo mismo que “tener pruebas”. Beck nos presenta el diagrama de “no tengo tiempo para test”. Básicamente, consiste en lo siguiente:
- Tu nivel de estrés aumenta
- Dedicas menos tiempo a testar, hay que correr
- Se cometen más errores
- Al haber más errores, el estrés aumenta
- El ciclo se repite
¿Cómo rompemos este ciclo? Si introducimos en este ciclo los tests automáticos, todo cambia. Si siento estrés, ejecuto los test, “uff, seguimos en verde, no hemos roto nada”. Cuanto más estrés tenga, más debo ejecutar los test, así podré saber que está todo bien o reducir los errores que hayamos cometido.
No tener tiempo es acabar muy estresados en el futuro, cuando la aplicación empiece a fallar y aumente nuestra ansiedad de que no llegaremos a todo lo que nos piden ¡Esta es la espiral de la muerte!
Es clave tener test aislados en TDD
Los test deben ser aislados, hacerse de manera que podamos ejecutarlos por nosotros mismos y hacerlo de manera frecuente. Muchas veces, un error en un test puede desencadenar una serie de errores en test futuros. Por eso, es clave que sean pequeños, así dividimos el problema y, en caso de fallo, lo detectamos rápido. Disponer de test aislados, además, nos facilita el poder ejecutar un subconjunto de ellos de manera independiente.
La lista de TO DO
Sabemos por clean code que, tener comentarios en el código o tareas pendientes suele dar muchos problemas. El “ya lo arreglaré” hace mucho daño al desarrollo. Hace años, tratando de testar un código Javascript para el que no conocía herramientas, puse varias alertas que decían “hola” y, así, saber dónde estaba el error.
En el libro, Kent Beck trabaja sobre un caso que va evolucionando de manera incremental para explicar diferentes maneras de mejorar un código y, sobre todo, cómo orientar las pruebas para gestionar nuestro desarrollo. Para evitar “ensuciar” nuestro código, Beck propone llevar una lista de tareas aparte, donde anotar las pruebas futuras o los retos que habrá que abordar. Así, si estamos atendiendo un determinado caso, podemos anotar sub-opciones que se nos hayan ocurrido ¡No buscamos la solución perfecta rápido!
Estrategias para tener “test en verde”
Cuando creamos un test o lo rompemos, lo tenemos en rojo, ¡tenemos que arreglarlo! Existen diferentes estrategias para conseguirlo. La más sencilla: hacerlo funcionar. Por ejemplo, si se nos ha roto un test porque no devuelve una operación lo que necesitamos, creamos una constante que lo haga ¡Listo! ¡Cuidado, ahora toca refactorizar! Puede parecer que algo tan obvio es negativo porque estamos creando un código que va a cambiar, pero esta es la base de la refactorización, ser simples al principio para mejorar nuestro desarrollo.
La clave para que una constante se convierta en un código más realista es usar la triangulación. Veamos un ejemplo.
Triangulación
Imagina que tenemos que probar la suma entre dos números:
suma(2,2) = 4;
La manera más sencilla de poner en verde nuestro test es crear una constante que devuelva siempre el número cuatro. Una vez tenemos el test en verde, toca mejorarlo. Por eso, creamos un segundo test, que probaría lo siguiente:
suma(2,3) = 5;
Devolver una constante no es suficiente, tenemos que volver a tener el test en verde. Ahora toca implementar la función. La aproximación por triangulación funciona bien cuando probamos operaciones más complejas, con algo tan sencillo usamos la aproximación por solución obvia.
Implementación Obvia
Sin embargo, la triangulación gana sentidos en problemas difíciles que debemos resolver con pequeños pasos (tiny-steps). A veces, estamos muy seguros de una determinada implementación, por ejemplo, con operaciones sencillas. Si tienes claro que lo puedes hacer rápidamente y puede funcionar, utiliza la implementación obvia, es decir, hazlo con el código final que crees que tendrá. Ahora bien, si falla, vuelve a las otras estrategias ¡Cuidado con la frustración que puede provocar el convivir con barras rojas cuando hemos querido ir demasiado rápido!
Uno a muchos
Por último, si queremos probar una operación que utiliza una colección de objetos, empezamos por uno solo y después lo escalamos. La clave de estas estrategias es convivir siempre con test verdes, así, con cada pequeño paso podemos validar que seguimos en verde y que está funcionando. Si implementamos pequeños cambios y ¡zas! aparece una barra roja, sabemos el paso que hemos dado y encontraremos la solución más rápido.
Por eso, TDD es mucho más que “test primero”, es el desarrollo orientado a test, es decir, es usar los test como mecanismo de avance en nuestro desarrollo de software.

Refactorizar, clave en TDD
TDD es mucho más que hacer test y desarrollar código. También, debemos refactorizar nuestro código. Refactorizar no debe cambiar la semántica de un programa bajo ninguna circunstancia. En TDD, la semántica la componen nuestros test, que para eso los hemos escrito. Por ejemplo, cambiar constantes por variables se puede considerar un ejercicio de refactorización, ya que los test continúan pasando. Sin embargo, cuando solo tenemos un test, podemos modificar nuestra semántica porque, dado que faltan, podemos entender que no estamos cambiando la semántica. Esto no evita que cometamos errores.
Por tanto, que todas las pruebas pasen no significa que esté funcionando correctamente. Si sabe que hay un problema y las pruebas pasan, entonces, escriba más test.
¿Cuándo debemos usar test y hasta qué nivel de profundidad?
La respuesta no es sencilla, un buen consejo es: “escribe test hasta que el miedo se transforme en aburrimiento”. La respuesta, por tanto, depende del programador. Por ejemplo, casi siempre deberías testear:
- Condicionales
- Iteraciones
- Operaciones
- Polimorfismo
Pero solo aquellos que tú escribas, no testees el código de otros. Si tienes relaciones con terceros, testea esa relación pero no el código de otra persona.
Kent Beck nos dejaba algunos consejos para saber si nuestros test eran buenos:
- Un setup muy largo: Si tenemos que escribir muchas líneas para un simple “assert”, entonces algo huele mal.
- Si tenemos un setup muy parecido a otro: posiblemente estamos testando a un nivel excesivo.
- Test muy duraderos: si un test necesta más de 10 minutos para ejecutarse, algo pinta mal porque lo ejecutaremos con poca frecuencia y perderemos la capacidad de desarrollar poco a poco. Preste atención al diseño.
- Test frágiles: si, de pronto, un test falla cuando estamos arreglando otra parte de la aplicación, puede ser una señal de que hay mucha cohesión entre partes.
Por tanto, estos consejos sirven para guiarnos, aunque está claro que el mejor consejo es practicar y probar. Al principio, costará más tiempo, pero las personas con experiencia en TDD vuelan en su desarrollo, y con mucha seguridad en lo que hacen. ¡Hay test en verde!
¿Es rentable usar TDD?
Kent Beck lanza una idea bastante interesante sobre la rentabilidad de TDD. Puede ocurrir que acabes construyendo la misma cantidad de código usando TDD que un desarrollo tradicional con pruebas al final. Desde el punto de vista económico, deberías poder escribir el doble de líneas de código al día o usar la mitad de líneas de código para la misma funcionalidad. Es clave integrar esta idea en nuestras métricas para demostrar que un desarrollo dirigido por pruebas tiene sentido.
Aún así, hay otra reflexión que podemos hacer si comparamos el enfoque TDD con otro tipo de aproximaciones, o peor aún, a no usar test automáticos. Cuando el desarrollo se orienta a pruebas, nos vamos a la cama con la “barra en verde”, es decir, sabemos que lo que está hecho funciona y eso nos permite dormir mejor por las noches. A veces, es mejor ir algo más despacio, pero mejorando la robustez, que correr sabiendo que, al terminar, las incidencias nos comerán todo nuestro tiempo.
Y tú, ¿practicas TDD?
Interesante guía, la comparto.