¿Qué es?
El desarrollo guiado por pruebas (TDD, Test Driven Development) se basa en la unión de dos prácticas: Test First y Refactoring.
Test first consiste en escribir las pruebas antes que el código. Dicho de otra manera, no se añade comportamiento nuevo si no hay antes una prueba que lo verifique.
El refactoring, a su vez, consiste en modificar la estructura (el diseño) de un sistema sin modificar el comportamiento.
La combinación de ambas técnicas nos permite distinguir dos “estados mentales” durante la creación de código: añadir comportamiento, en el que nos centramos en la calidad de las pruebas, y añadir estructura, en el cual nos centramos en la calidad del diseño.
¿Para qué se hace?
Fundamentalmente, para escribir código limpio que funciona. La principal ventaja del código escrito mediante TDD es que sabemos que funciona y podemos demostrarlo pasando las pruebas.
Como resultado “secundario”, al escribir las pruebas antes que el código, nos aseguramos de que tenemos un conjunto suficientemente amplio de pruebas de regresión lo que nos permitirá ser más atrevidos durante la fase de refactoring ya que sabemos que, en caso de “romper” alguna funcionalidad, las pruebas lo detectarán.
Otra ventaja es que las pruebas documentan el comportamiento del código de manera inambigua y verificable (propiedades básicas de cualquier especificación) y, además, no se quedan obsoletas ya que, si cambia el código que documentan en alguno de los aspectos documetados, dejan de pasar.
Por último, también creo que es importante destacar el cambio de punto de vista a la hora de diseñar la interfaz pública de nuestro código (la API). Si empezamos escribiendo la implementación, lo habitual es pensar en métodos que tengan sentido desde el punto de vista de la implementación y, en cierta manera, que nos sean fáciles de implementar. En cambio, si empezamos escribiendo las pruebas, pensaremos en métodos que sean fáciles de llamar y que tengan un conjunto claro de responsabilidades para que la prueba sea fácil de escribir.
¿Cómo se hace?
La clave está en conseguir un ritmo más o menos estable; lo que se conoce como ‘red-green-refactor’.
Red hace referencia a la escritura de la prueba para el comportamiento que queremos añadir: Al escribir la prueba ésta debe fallar (y la herramienta de pruebas suele pintar una barra roja en este caso). Si la prueba no falla, o bien está mal o el comportamiento probado no es nuevo.
Green (verde) es el color de la barra cuando la prueba pasa; en este paso nos centramos em conseguir la implementación más simple posible del comportamiento. En cuanto pasa la prueba hay que parar de añadir comportamiento ya que éste no estaría cubierto por ninguna prueba (resistir la tentación de seguir añadiendo comportamiento es una de las cosas que más cuestan al principio).
Refactor, el último paso, es cuando aprovechamos para ‘ordenar la casa’ y pensar en el diseño y arquitectura. Al hacerlo después de pasar la prueba ganamos que sólo añadiremos complejidad si vemos un beneficio claro (si no lo vemos, la tendencia natural será quedarnos con el código que ya tenemos y funciona).
Para establecer un ritmo constante (y ser más productivos) es recomendable que el ciclo se repita con frecuencia, por lo que se aconseja avanzar a pasos pequeños (baby steps).
¿Qué se necesita?
La mayoría de entornos modernos de desarrollo incluyen algún tipo de soporte a pruebas automatizadas (al estilo de JUnit en java). Eso sí, para que la ejecución de pruebas no sea percibida como un lastre, es vital que la ejecución de las mismas sea rápida (del orden de segundos) y cómoda (por ejemplo, como un paso más de la ‘build’). En este sentido, lo ideal sería contar con una herramienta de testing contínuo como infinitest o junit max).
Tradicionalmente, TDD se ha asociado a pruebas unitarias, aunque el mismo enfoque (test first + refactoring) podría aplicarse a otras pruebas como las de integración o las de aceptación. En estos casos, necesitaremos herramientas adicionales que nos faciliten la ejecución de las pruebas (preparar la base de datos, inyectar dependencias, etc.) y, además, deberemos tener en cuenta que suelen ser más lentas de ejecutar (y, por lo tanto, es más fácil que se conviertan en un lastre y las dejemos de ejecutar).
¿Dónde puedo aprender más?
Una buena manera de aprender a hacer TDD es programar en pareja con alguien que lo haya hecho anteriormente. Los coding dojo son una buena oportunidad para hacerse una idea aproximada de cómo es desarrollar así (eso sí, la experiencia dependerá mucho de la pareja escogida). En ellos, se desarrolla un ejercicio (code kata) conocido de antemano centrándose en hacerlo de la mejor manera posible, y por eso es habitual hacerlos mediante TDD. También podemos mirar un screencast como los de 12meses12katas.
En cuanto a bibliografía, el primer artículo que leí sobre el tema fue “Test Infected” y creo que ha resistido bastante bien el paso del tiempo aunque éste de agiledata.org también está muy bien. A nivel de libros, tenemos la suerte de disponer del libro de Carlos Ble “Diseño ágil con TDD“ (gratuito y en castellano) o el del creador de JUnit Kent Beck (Test Driven Development: By Example). Si lo que queremos es profundizar en la materia, Growing Object Oriented Software, Guided by Tests de Steve Freeman y Nat Price ofrece una visión más avanzada del uso de pruebas para dirigir el desarrollo de software.


Gracias por recomendar nuestro libro