¿Qué es el desarrollo basado en pruebas (TDD)?
Agile 101
Desarrollo Dirigido por Pruebas o TDD
¿Qué es el desarrollo dirigido por pruebas (TDD)?
El Desarrollo Dirigido por Pruebas es un proceso en el que se escriben las pruebas antes de escribir el código. Y cuando todas las pruebas pasan, se limpia la cocina: se mejora el código.
Sin embargo, el Desarrollo Dirigido por Pruebas no es sobre las pruebas
La premisa detrás del desarrollo dirigido por pruebas, según Kent Beck, es que todo el código debe ser probado y refactorizado continuamente. Eso suena como si se tratara de pruebas, así que ¿qué pasa?
Bueno, las pruebas que escribes en TDD no son el punto, sino el medio.
El punto es que al escribir pruebas primero y esforzarse por mantenerlas fáciles de escribir, estás haciendo tres cosas importantes.
-
Está creando documentación, especificaciones vivas y nunca obsoletas (es decir, documentación).
-
Está (re)diseñando su código para hacerlo y mantenerlo fácilmente comprobable. Y eso lo hace limpio, sin complicaciones y fácil de entender y cambiar.
-
Está creando una red de seguridad para hacer cambios con confianza.
¿Cuáles son los Beneficios del Desarrollo Dirigido por Pruebas?
Además de los beneficios mencionados en la sección anterior, el TDD también le consigue:
-
Notificación temprana de errores.
-
Diagnóstico sencillo de los errores, ya que las pruebas identifican lo que ha fallado.
Lo que todo esto significa para su negocio, es:
-
Mejora su factor de bus, ya que el conocimiento no está solo en las cabezas y facilita la incorporación de nuevas contrataciones.
-
Reduce el coste de las mejoras. Mantener el código limpio es también la forma de minimizar el riesgo de complicaciones accidentales. Y eso significa que podrá mantener un ritmo constante en la entrega de valor.
-
Con la red de seguridad, los desarrolladores están más dispuestos a fusionar sus cambios y a incorporar los de otros desarrolladores. Y, lo harán más a menudo. Y entonces el desarrollo basado en el tronco y la integración, entrega y despliegue continuos pueden despegar realmente.
-
Disminuye el número de errores que se «escapan» a la producción y eso reduce los costes de soporte.
La Sorprendente Razón para Utilizar el TDD
Si todos estos beneficios no son suficientes, hay una razón más para usar TDD, una que le sorprenderá.
Kent Beck lo expresa de esta manera: «Sencillamente, el desarrollo dirigido por pruebas tiene como objetivo eliminar el miedo en el desarrollo de aplicaciones».
El miedo es bueno para mantenerse vivo, pero es un asesino para el trabajo que necesita la más mínima cognición.
¿Y qué hay de «Los desarrolladores no deben escribir las pruebas para probar su propio código?”
Sí, hay buenas razones para no dejar que los desarrolladores escriban las pruebas para probar su propio código.
Sin embargo, este consejo se aplica a las pruebas a nivel de aplicación.
Para las pruebas a nivel de desarrollador, hacer que otra persona escriba las pruebas es como enganchar el caballo detrás del carro.
Los requisitos suelen estar varios niveles de abstracción por encima del código necesario para implementarlos. Así que tiene que pensar bien lo que necesita hacer y cómo lo hará. Escribir las pruebas primero es una forma excelente y eficiente de hacerlo.
Y, recuerde, TDD no es sobre las pruebas.
¿Y dónde encaja el desarrollo dirigido por pruebas en Agile?
Ya en 1996, el equipo del proyecto C3 de Chrysler practicaba la programación basada en las pruebas. «Siempre escribimos pruebas unitarias antes de liberar cualquier código, normalmente incluso antes de escribir el código», dice el estudio de caso sobre el proyecto titulado “Chrysler Goes to “Extremes”.
Escribir primero las pruebas era sólo una de las prácticas utilizadas por el equipo C3. En conjunto, estas prácticas se conocieron como programación eXtreme. Tres miembros de ese equipo, Kent Beck, Martin Fowler y Ron Jeffries, estuvieron entre las personas que escribieron y firmaron por primera vez el Manifiesto Ágil.
El desarrollo basado en pruebas es una práctica ágil fundamental. Apoya directamente el valor ágil de «el software de trabajo por encima de la documentación exhaustiva». Y lo hace protegiendo el software de trabajo con pruebas y creando la documentación como un subproducto natural.
Bien, ¿Cómo se Practica el TDD?
Src: Spec-india.com
El desarrollo dirigido por pruebas es engañosamente sencillo. Es fácil explicar lo que se hace, pero no es tan fácil hacerlo. Más sobre el porqué de esto, en la siguiente sección. En primer lugar, vamos a explicar lo que se hace en TDD.
The Cycle and Stages of TDD
El Ciclo y las Etapas del TDD
El Desarrollo Dirigido por Pruebas significa pasar por tres fases. Una y otra vez.
-
Fase roja: escribir una prueba.
-
Fase verde: hacer que la prueba pase escribiendo el código que vigila.
-
Fase azul: refactorizar.
Las Reglas del TDD según el Tío Bob
El tío Bob (Robert C. Martin) expuso las reglas de TDD en el capítulo 5 Desarrollo Dirigido por Pruebas de su libro The Clean Coder.
-
No se permite escribir ningún código de producción a menos que sea para hacer pasar una prueba unitaria que falla.
-
No se permite escribir más de una prueba unitaria que sea suficiente para que falle; y los fallos de compilación son fallos.
-
No se permite escribir más código de producción que el suficiente para pasar la prueba unitaria que falla.
¿Por qué seguir estas reglas? Porque están pensadas para hacerle la vida más fácil.
Pero no estoy contento con la regla #2. Porque tratar los errores de compilación como fallos puede enmascarar el hecho de que una prueba no tiene aserciones. Y eso es malo, porque puede hacerle pensar que una prueba está pasando cuando el código está (en parte) sin escribir o simplemente equivocado.
Dicho esto, la intención de las reglas es mantener las cosas enfocadas en cada fase y evitar que se caiga en agujeros de conejo. Por experiencia, eso ayuda mucho a mantener las cosas claras en su cabeza. Así que:
-
Durante la fase roja (escritura de la prueba), trabaje sólo en el código de prueba.
-
Una prueba que falla es buena. Al menos si es la que estás trabajando. Todas las demás deben ser verdes.
-
Durante la fase verde (hacer que la prueba pase), sólo trabaja en el código de producción que hará que la prueba pase y no refactorices nada.
-
Si la prueba que acaba de escribir falla significa que su implementación necesita trabajo. Si otras pruebas fallan, ha roto la funcionalidad existente y necesita retroceder.
-
Durante la fase azul (refactorización), sólo refactoriza el código de producción y no haga ningún cambio funcional.
-
Cualquier prueba que falle significa que ha roto la funcionalidad existente. O bien no ha completado la refactorización, o necesitas dar marcha atrás
Ejemplo de uso del TDD
Hagamos todo lo anterior un poco más concreto con un ejemplo. Supongamos que se le encomienda la tarea de crear un método que convierta los números decimales en romanos.
Paso 1: Fase roja, escriba una prueba.
El decimal 1 debe devolver «I».
Ejecutar la prueba no es posible en este momento, porque la clase Romanizer no existe todavía y eso significa errores de compilación.
Paso 2: Fase verde, hacer que la prueba pase
Añada la clase Romanizer y dele un método FromDecimal que tome un entero y devuelva una cadena.
Me gusta asegurarme de que la prueba sigue fallando cuando el código se compila. Así sé que empiezo con una prueba que falla como resultado de las aserciones en las pruebas.
Así que escribo una implementación que estoy seguro que fallará.
¿Tonterías? No. El código es correcto y hace que la prueba pase..
Idear un algoritmo que pueda funcionar es prematuro a estas alturas. Es posible que acierte, pero es más probable que no lo haga. Y eso puede ponerle en un aprieto (ver más abajo).
Paso 3: Fase azul, refactorizar
No hay mucho que refactorizar todavía, así que a la siguiente prueba.
Paso 4: Fase roja, escribir una prueba
El decimal 2 debería devolver «II».
Hmm. I don’t like if-else-if constructs much, but let’s run the tests first.
Bien. Pasamos a la fase verde.
Paso 5: Fase verde, hacer que la prueba pase
De nuevo, escribe el código más sencillo que haga que la prueba pase.
Step 7: Red phase, write a test
Decimal 3 should return “III”.
Hmm. No me gustan mucho las construcciones if-else-if, pero hagamos primero las pruebas.
Paso 7: Fase roja, escribir una prueba
El decimal 3 debería devolver «III».
Y ejecutar todas las pruebas para ver esta falla. (¡Y ninguna otra!)
Paso 8: Fase verde, hacer que la prueba pase
De nuevo, el código más sencillo para hacer pasar la prueba.
Esto empieza a oler muy mal, pero primero haga las pruebas.
Sí, todo verde, así que por fin podemos hacer algo con esa construcción if-else-if, porque 3 casos sí merecen una refactorización ya que ahora se aplica la Regla de 3.
Paso 9: Fase azul, refactorización
El patrón está claro. Se necesita tantos «I» como el número que se ha pasado.
Ejecute todas las pruebas para asegurarse de que cada una de ellas sigue pasando.
Algunas reflexiones adicionales
Reglas de Refactorización
Cuando se refactoriza, no se hace al azar. Sino que sigues un proceso estructurado para limpiar el código.
Se identifican los olores del código y se aplica una refactorización específica para eliminarlos. Martin Fowler escribió el libro sobre cómo hacerlo: Refactoring: Improving the Design of Existing Code.
El propósito de la refactorización es mejorar la extensibilidad de su código mediante
-
mejorar la legibilidad
-
facilitar la realización de cambios
-
reducir la complejidad
-
mejorar la arquitectura interna (modelo de objetos) y hacerla más expresiva
Lo que es realmente importante es que la refactorización es lo que consigue un código limpio y sin complicaciones que es fácil de entender, cambiar y probar. Y ya ha leído lo que se consigue con eso.
¿Por qué es tan difícil practicar TDD?
Practicar TDD no es un camino de rosas. Al menos no al principio. He aquí las razones.
-
Porque hay que pensar en lo que se quiere conseguir con el código y en cómo protegerlo para que no se rompa (probarlo).
-
Porque tiene una curva de aprendizaje muy pronunciada. Es necesario aprender los principios y patrones de diseño para crear un código limpio y cómo refactorizarlo para mantenerlo así.
-
Porque el código se defiende. El código existente que no está bajo prueba te pilla entre la espada y la pared. Necesita refactorizarlo para ponerlo bajo prueba y necesitas pruebas para refactorizarlo. Recomiendo encarecidamente Working effectively with Legacy Code de Michael C. Feathers para esto.
-
Porque se experimentan los costes de TDD inmediatamente y el coste de no hacerlo mucho más tarde. El atractivo de dejarlo pasar es fuerte. Usted sabe que va a pagar el precio cuando los informes de errores comienzan a inundar. Pero eso es más tarde, ¿no?
¿Cómo se puede fracasar en el TDD? ¿Cuáles son los errores más comunes?
Se puede fracasar en la práctica de TDD de muchas maneras:
-
No seguir el enfoque de «primero la prueba».
-
No refactorizar todo el tiempo.
-
Escribir más de una prueba a la vez.
-
No ejecutar las pruebas con frecuencia, perdiendo la retroalimentación temprana de las mismas.
-
Escribir pruebas que son lentas. Todo el conjunto debería completarse en minutos o incluso en segundos.
-
Usar sus pruebas unitarias para hacer pruebas de integración. No hay nada malo en utilizar su marco de pruebas unitarias para ejecutar pruebas de integración. Pero las pruebas de integración son, por naturaleza, lentas, así que debes ponerlas en su propio conjunto de pruebas.
-
Escribir pruebas sin aserciones.
-
Escribir pruebas para el código trivial, como los accesores y las vistas sin lógica.
Recursos para Aprender y Mejorar
-
The original text on TDD: Test Driven Development, By Example by Kent Beck.
-
Working effectively with Legacy Code by Michael C. Feathers.
-
Refactoring: Improving the Design of Existing Code by Martin Fowler.
-
The Art of Unit Testing: With Examples in c# by Roy Osherove
-
Growing Object-Oriented Software, Guided by Tests by Steve Freeman
-
Clean Code: A Handbook of Agile Software Craftsmanship by Robert C. Martin (Uncle Bob)
-
The Clean Coder: A Code of Conduct for Professional Programmers by Robert C. Martin (Uncle Bob)
¿Cuál es la diferencia entre TDD y BDD??
El desarrollo dirigido por el comportamiento y el desarrollo dirigido por las pruebas son similares y diferentes al mismo tiempo.
No espere, Vaya Tras Su Lecho De Rosas
¡La vida es buena cuando sus equipos ágiles están sincronizados!
Solicite una demostración personalizada de SwiftEnterprise.

