Test Driven Design – TDD

El diseño dirigido por test cada vez tiene mas importancia y poseer esta skill es cada vez más valorado. En la actualidad la realización de unit test casi siempre se relega a un segundo plano, y se hace aprisa y corriendo si sobra algo de tiempo en cada release, o se pasa de puntillas sobre este tema para cubrir el expediente como algo burocrático que hay que escribir.

Si se hace una buena batería de test, con sentido, de forma que el código quede bajo cobertura de los test, y los test cubran a su vez las posibles casuísticas, tu aplicación tendrá una muy alta probabilidad de evitar o detectar bugs, de ser mantenible, confiable, de no tener miedo a introducir cambios o mejoras en el código porque tus test detectarán tus errores.

Todo esto estará conseguido si sigues TDD, ya que como voy a explicar, todo tu código se soportará sobre test creados con anterioridad.

¿Qué es TDD?

TDD es una metodología de trabajo, en la cual antes de comenzar a escribir código sobre la funcionalidad que vas a desarrollar, preparas los test, paso a paso, para que la prueba sobre dicha funcionalidad falle, debido a que la implementación de la funcionad aún no estará escrita o desarrollada.

Esta metodología se puede simplificar en 3 pasos.

  • Rojo: Escribe un test que falle, pretendiendo probar una funcionalidad que debe ser cierta
  • Verde: Escribe el código que haga que dicho test de un resultado positivo, lo cual implica que esa funcionalidad será cierta.
  • Refactorizar: Refactoriza tu código para seguir buenas prácticas.

En el tercer paso vuelves al primero, hasta que termines de desarrollar la funcionalidad completa.

¿Cómo se lleva esto a la práctica?

Vamos a reutilizar un ejemplo simple que cree en esta entrada para describir que son los unit test. En ese ejemplo realizo una comparación de 2 byte[] para controlar la concurrencia a través de RowVersion.

Comenzaré por definir la interfaz.

Ahora creo la implementación de dicha interfaz, pero aún no comenzamos a escribir el código de la funcionalidad.

Ahora creo la clase de test donde iremos haciendo todos los test que describirán la funcionalidad.

En este primer test estoy validando que si los parámetros son null, el resultado será una excepción de tipo ArgumentNullException con el mensaje ValidationMessage.TXT_ParameterNull. Si ejecutamos el test arrojará un resultado negativo puesto que ahora mismo la implementación solo devuelve una excepción de NotImplementedException. Así que voy a remediarlo para que dé verde.

Ahora voy a añadir el test para verificar la comprobación de los dos objetos byte[], para crear un nuevo test rojo y progresar en la creación de la funcionalidad mediante TDD.

Este nuevo test ValidateConcurrency superará el if que devuelve la excepción de ArgumentNullException, pero la implementación aún no responde a lo que estoy buscando, así que dará rojo y creo la implementación de nuevo.

El test sigue dando rojo, obviamente no puedo comparar con “==” dos objetos de tipo byte[], asi que lo arreglo.

Ahora el test da verde porque en caso de que los dos objetos de entrada coinciden, como esta ocurriendo en el test ValidateConcurrency de la clase ServiceTest, así que SequenceEqual devolverá true y el Assert.IsTrue(actual) se verificará adecuadamente.

Con esto todo nuestro código esta bajo cobertura de test ¿pero están cubiertas todas las casuísticas? En este caso el ejemplo es muy simple, y obviamente si las cadenas no coinciden el test devolverá false, pero voy a asegurarme de ello con otro test, ya que es buena práctica cubrir todas las diferentes casuísticas del comportamiento que se espera de tu SUT. En casos mas complejos no es solo una buena práctica, si no algo muy recomendable porque el resultado no será tan obvio.

Ahora ya esta mi batería de test. Verifico el comportamiento cuando no tengo parámetros de entrada, cuando estos son iguales, y cuando estos son diferentes. Tengo toda mi casuística bajo cobertura de test y todo mi código a su vez esta bajo cobertura de esos test.

Este caso es muy simple, no se relaciona con ninguna otra clase, ni tiene una lógica completa, pero ese no era el objetivo de esta entrada, solo dar una vista superficial de que en consiste la metodología TDD. En otras entradas habrá oportunidad de ir haciendo test a códigos mas complejos.

 

Deja un comentario