- El modelo tradicional no favorece la escritura de testing unitario
- Test Driven Development nos ayuda a evitar estos problemas
- ¿Qué es Test Driven Development (TDD)?
- Uso de la técnica de pair programming “Ping Pong”
- ¿Qué tiene esto que ver con DevOps?
En el anterior artículo “La importancia del testing en DevOps” comentamos el por qué de la necesidad de implementar una buena estrategia de testing dentro de nuestra implementación del modelo DevOps.
Como vimos, la parte fundamental de la pirámide del testing es el nivel del testing unitario. En este artículo vamos a explicar cómo el uso de Test Driven Develoment nos va a ayudar a conseguir esa sólida base de testing.
El modelo tradicional no favorece la escritura de testing unitario
En los desarrollos tradicionales el testing unitario normalmente se escribe, en el mejor de los casos, una vez que se ha desarrollado la funcionalidad. Uno de los problemas típicos con los que nos encontramos es que, debido a problemas con los tiempos de entrega, muchas veces se elimina esta fase de escritura de tests. Por otro lado, si pasa mucho tiempo entre que escribimos la funcionalidad y escribimos los tests, la tarea nos resulta mucho más laboriosa. Por último, al desarrollar las funcionalidades sin tener en mente que después serán puestas a prueba, nos encontramos con código que es muy difícil, a veces imposible, de probar.
El problema se agrava si añadimos que haya equipos separados que escriben tests unitarios y que son distintos de los programadores que escribieron el código. Esto nos lleva a la primera regla que debemos cumplir a la hora escribir tests unitarios:
“Los propios desarrolladores son los que escriben sus tests unitarios“
Test Driven Development nos ayuda a evitar estos problemas
Una técnica de desarrollo que nos ayuda a evitar estos problemas es Test Driven Development que en muy pocas palabras establece que los tests de nuestro código deben ser escritos antes que el código en sí.
Mucha gente piensa erróneamente que TDD es una herramienta de testing, cuando en realidad es una técnica de Diseño y Desarrollo de software que tiene como efecto colateral que se generan multitud de tests unitarios. Por tanto, el alto grado de cobertura de testing no es el principal objetivo de TDD, sino un efecto secundario.
Otros beneficios que se obtienen con el uso de TDD son la simplicidad del código que generamos, que el código creado siempre puede ser sometido a test, una documentación actualizada y ejecutable ya que los propios tests nos sirven para este fin, el número de errores se reduce drásticamente y a la larga reduce los tiempos de desarrollo y mantenimiento.
Por último, el escribir los tests antes que el código establece claramente cuando se ha terminado una tarea: cuando se han pasado todos los tests que requiere la funcionalidad desarrollada.
¿Qué es Test Driven Development (TDD)?
El proceso que describe TDD, o como se denomina normalmente, el TDD Mantra, en realidad es muy sencillo como se puede observar en la siguiente figura.
Fase Red
Partimos siempre de la fase Red en la que, a partir de un requisito, historia de usuario o aquel elemento que nos describa la funcionalidad, escribimos el test o tests que validarán dicha funcionalidad. Esta fase se denomina Red porque es el color de error de los tests fallidos. Siempre partimos de un test fallido.
Fase Green
Una vez que tenemos el test fallido, implementamos el código más simple que haga pasar este test fallido. Este código no tiene que ser el más elegante o eficiente. El objetivo es llegar a un punto seguro y estable moviéndonos en pequeños pasos. Es aquí donde seguimos el principio KISS: Keep it Simple, Stupid.
En este punto podemos pasar a la fase de refactoring o volver a la fase Red en la que escribamos un nuevo test que rompa la implementación que hayamos desarrollado.
Un elemento clave de este proceso es la rapidez. El paso de la fase Red a Green y viceversa tiene que ser muy rápido, de algunos minutos. Si tardas horas en cambiar de fase, ten en cuenta que lo estás haciendo mal.
Fase Refactor
Una vez que hemos escrito una serie de tests o simplemente un test, entramos en la fase de refactoring en la que mejoramos el código sin modificar la funcionalidad. Un error común en la esta fase es cambiar la funcionalidad en vez de mejorar el diseño. Para esta fase es muy recomendable seguir los patrones típicos de refactoring.
Al finalizar esta fase obtenemos un código limpio, simple y eficiente.
Si repetimos este ciclo obtendremos un código que puede ser probado y ha superado el test, con un diseño lo más simple posible elaborado de manera incremental e iterativa.
Uso de la técnica de pair programming “Ping Pong”
Aprender a desarrollar usando Test Driven Develpment puede ser muy complicado porque entra en conflicto con algunas de las asunciones básicas como, por ejemplo, suponer que el código tiene que estar escrito para poder ponerlo a prueba y que la fase de testing va después de la fase de desarrollo.
En este punto es fundamental recordar que el testing es una actividad y no una fase del desarrollo de software.
Una técnica que en particular resulta útil para mejorar en el desarrollo con TDD es la modalidad de pair programming llamada “ping pong». A parte de ser una práctica entretenida, proporciona todos los beneficios del pair programming, por lo que merece la pena darle una oportunidad.
En esta modalidad la pareja sigue el siguiente protocolo:
- Un miembro de la pareja escribe un test fallido y le pasa el control a su compañero.
- El compañero escribe el código que pasa el test, realiza algún grado de refactoring y seguidamente escribe un nuevo test fallido y le devuelve el control a su compañero.
- Se repite el ciclo como si una partida de ping pong se tratara.
En la siguiente imagen se puede ver el proceso.
¿Qué tiene esto que ver con DevOps?
¿Cómo beneficia el uso de Test Driven Development a la implementación de un modelo DevOps?
Como comentamos al principio del artículo, disponer de una sólida base de testing unitario es fundamental y un habilitador de la entrega continua. Con el uso de TDD obtenemos esta base y sentamos los fundamentos de nuestra estrategia de automatización de pruebas. Con esta base mejoramos la fiabilidad de nuestro código y aumentamos la confianza en nuestra pipeline de despliegue. Por otro lado, el propio proceso de TDD nos obliga a avanzar en pequeños pasos, siendo esto un elemento fundamental para el éxito de una implementación DevOps como ya vimos en el artículo sobre el uso de small batches.
Por tanto, el uso de TDD realmente nos ayuda en gran medida en nuestra tarea de implementar un modelo DevOps.
En próximos artículos veremos otras estrategias de testing que nos ayudarán en otros niveles de nuestra pirámide de automatización de las pruebas.
Emiliano Sutil es Project Manager en Xeridia