La desorientación con las pruebas…

Para muchos desarrolladores la orientación a pruebas es el pan de cada día. Pero muchos, sobre todo aquellos recién saliditos de la universidad no saben ni con qué se come el TDD. Si usted ya sabe de qué va la cosa, le pido que me audite y me ayude a hacer una nota inteligente y completa, si usted no sabe ni de qué estoy hablando, tendrá que suponer que tengo un mínimo razonable de idea del asunto y no le quedará otra que creerme o seguir buscando en Google.

Alguna vez una señora muy ocupada estaba corriendo de un lado al otro de la casa y su sirvienta le dijo “Hay señora, usted hace que hace pero no hace nada”. Esta frase tiene su encanto en su contexto original, pero tiene también importancia en el desarrollo orientado a pruebas pues de eso se trata muchas veces una prueba, “hacer como que hace sin hacer nada”. No me malentienda, las pruebas si hacen, hacen mucho, pero a veces es necesario no hacer nada para saber que lo que se hace se hace bien.

La primera impresión de muchos programadores al enfrentarse con las pruebas unitarias es de desconfianza, ¿Para qué perder tiempo escribiendo pruebas que en muchos casos son más del doble en código que el código verdadero? ¿Porqué probar hasta los métodos más simples y elementales?

La respuesta a estas preguntas suele llegar sóla después de un tiempo de trabajar con las pruebas unitarias y los desarrolladores que las usan no ven cómo habían podido vivir sin ellas. Usarlas es convencerse uno mismo que ese supuesto tiempo perdido es en realidad un gran ahorro a mediano y largo plazo no sólo de tiempo, sino de esfuerzo.

Las pruebas unitarias son en realidad algo más que sólo verificación de funcionalidad, son documentación de código, traducciones en código de requerimientos y un seguro de gastos médicos a lo largo del desarrollo. Es esta versátil funcionalidad lo que dio lugar al Desarrollo orientado a pruebas que es parte escencial de la metodología XP. [pruebas unitarias en XP]

En el desarrollo orientado a pruebas hay una máxima que no debe ser olvidada: “El único código que nunca falla es el que no se implementa”, y de aquí que su primer paso sea Escribir una prueba. Por supuesto, la prueba falla o debe fallar al principio, pues no se ha escrito el código que la valida, de hecho, el código puede no compilar y es lo normal. La prueba representa uno o varios requerimientos establecidos en un guión de usuario (caso de uso o tarjeta de responsabilidades) y documenta el uso del código que debe evaluar.

El segundo paso es Correr las pruebas y verificar que la nueva falla, si la nueva prueba no fallase es posible que la funcionalidad haya sido “escrita” antes de tener su prueba, lo que sin duda es un riesgo, pues indica que tenemos código sin probar.  Aquí hay que notar que el hecho de que el compilador no sea capaz de compilar es equivalente a que la prueba falle en este paso.

El tercer paso es Escribir el código necesario para que la prueba pase. Aquí volvemos a recordar la máxima, pues sólo se debe escribir el código necesario y suficiente para pasar la prueba, no importa en este momento ni la elegancia del código ni su eficiencia, eso lo dejaremos para dentro de unos pasos más.

El cuarto paso es Correr todas las pruebas y verificar que todas pasan. Si la prueba con la que estamos trabajando no pasa, hay que volver al código y arreglarlo para que pase, si alguna otra prueba dejó de pasar, es el mejor momento para averiguar porqué y arreglar el código, pues las adiciones o modificaciones que hicimos están afectando a otras funcionalidades. En algunos casos habrá que cambiar las pruebas, pero sólo si es necesario. Aquí es donde se hace evidente la seguridad que confieren las pruebas durante el desarrollo, pues los errores se localizan casi tan rápido como se producen.

El quinto paso es Refabricar el código (Refactoring). Refabricar el código es “volverlo elegante”, quitar el código duplicado mediante la creación de métodos internos, reducir su complejidad y mejorar su legibilidad (recuerde que el código es escrito por humanos y son humanos quienes lo leeran en caso de errores o mantenimiento, entre más fácil de leer, más fácil de utilizar). Por supuesto, la refabricación de código puede romper las pruebas, por ello es necesario el último paso.

El sexto paso es volver a Correr todas las pruebas y verificar que todas pasan para asegurarnos que la refabricación no descompuso algo que sí funcionaba bien.

Llegados a este punto, el procedimiento vuelve a comenzar, a pequeños pasos, funcionalidad por funcionalidad, el desarrollo irá tomando forma mientras nos aseguramos de su correcta implementación y lo vamos documentando como de pasada.

Una explicación más completa de esta técnica, y sin duda una de las más famosas es la que ofrece Kent Beck en su libro Test Driven Development: By Example (Addison-Wesley Signature Series) by Kent Beck (Paperback – Nov 8, 2002).

 A veces esta receta se complica un poco, el ejemplo tradicional de tales complicaciones es en el cosumo de bases de datos o servicios de otros sistemas, donde las pruebas pueden ser demasiado elaboradas o consumir demasiado tiempo o simplemento ser imposibles por inaccesibilidad del segundo sistema.

El primer principio de las pruebas que modifican un sustrato de datos es que si el sistema interactua con el sustrato real de datos durante las pruebas, el sustrato debe terminar en el mismo estado en el que estaba antes de la prueba, esto es, debe parecer que no pasó nada después de correr la prueba. Pero como ya comentamos, a veces este tipo de operaciones no son del todo convenientes y pueden evitarse con el uso adecuado de patrones de diseño. En este caso, nuestras pruebas de funcionalidad no tienen porque obligar una interacción real con el sustrato de datos, sino con un “impostor” (Mock object) que se comporte igual. Esto es, “hacer como que hacen pero sin hacer nada”. A cerca de este tipo de técnicas, un libro muy interesante es Test-Driven Development in Microsoft .NET (Microsoft Professional) by James W. Newkirk and Alexei A. Vorontsov (Paperback – April 14, 2004), los autores de este libro han estado involucrados en el desarrollo de la herramienta de orientación a pruebas para el entorno .Net de Microsoft, NUnit.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s