Si pruebas, repites – unit testing 101
Cuando ejecutamos nuestros desarrollos para ver cómo funcionan, ver si cascan, ver si todo se comporta como se espera, si esa nueva funcionalidad devuelve lo que debe… estamos probando nuestro código.
De hecho solemos ir más alla, porque solemos incluir cierto código de vez en cuando para ver que funciona todo, ¿no?. Podíamos decir que tenemos cierto nivel de automatización.
Por ejemplo, digamos que tengo un método que normaliza un string en base a ciertas reglas a nivel de negocio (referencias, caracteres especiales…) Ya sea en ese proyecto u otro, antes de acabar la aplicación, nos creamos algunas líneas de código para probar el método y ver el resultado en pantalla, así vemos que funciona como debe. En ese momento tenemos una prueba, un elemento que nos puede ayudar a hacer un desarrollo iterativo asegurándonos la consistencia de lo que ya tenemos y avisandonos de si introducimos algún problema… pero LO BORRAMOS!!
Ahora, si en el futuro incluimos algo de código que rompa esa conversión, tendremos que investigar a ver qué parte se ha roto prácticamente desde cero. Porque con el sistema crecido, puede que no veamos el error de conversión, si no, un fallo en un control de la interfaz, al consumir un servicio web, en un XML… hala… a perder el tiempo :_)
Pruebas de andar por casa, que sirven perfectamente
Imaginad que hubiesemos guardado ese código. Algo simple, olvidad los frameworks de testing y demás vainas. Simplemente añadir un proyecto nuevo a la solución que se llame pruebas. Que tenga una clase con un método que se llame probar y dentro de ese método vamos validando nuestro código…
Cada vez que vamos generando nuevo código, borrando o refactorizando, ejecutamos ese proyecto para ver si todo lo que funcionaba SIGUE funcionando.
¿No crees que sería una forma ÓPTIMA de desarrollar? dicho de otro modo, ¿no crees que es una forma genial de asegurarnos de que nada nuevo rompe nada de lo que hay hecho? Nos evitaríamos un montón de bugs tontos!!
En una segunda vuelta, se nos podría ocurrir generar pruebas para asegurar que el código falla cuando tiene que fallar ¿no? Saber qué la aplicación solo se comporta como debe, cuando debe, también es importante. Además de que el hecho de que los errores y las excepciones sean los esperados en cada caso es importante. También son parte del funcionamiento del sistema y deberíamos asegurarnos de que funcionen cómo y cuando deben :)
Las pruebas no son la bala de plata contra los bugs, por mucho que las hagamos los bugs aparecen, en menor medida, pero aparecen. ¿Qué debemos hacer cuando aparece un bug? Podemos corregirlo sin más, pero para seguir manteniendo la consistencia, lo primero que deberíamos hacer es el test correspondiente al fallo, la prueba que demuestra que es un bug. A partir de ese momento, cuando este corregido, será una prueba más que nos asegura la consistencia del sistema. Tendremos ese escenario y los adyacentes mejor asegurados para el futuro.
Los frameworks de testing
Muchos hacéis las pruebas como hemos dicho en el apartado anterior, es hora de que déis el salto!! Un framework de testing nos ayuda a hacer las pruebas de una forma más sencilla y nos proporciona información sobre el código probado. Por ejemplo, automatiza las llamadas a los métodos de prueba, genera informes de resultados integrados en el propio entorno de desarrollo, dan mayor granularidad porque permiten lanzar solo ciertas pruebas, etcétera…
Hay numerosos frameworks, normalmente, si sabes uno, cambias algo la sintaxis y sabes todos, no hay grandes cambios. Personalmente utilizo el MSTest porque viene integrado con Visual Studio.
Para poner un ejemplo, partiendo de la idea de antes, podríamos agregar un nuevo proyecto de testing a la solución con un código como el siguiente:
Es prácticamente lo mismo que teníamos, pero con una mejor organización, decorado con atributos y teniendo un informe de resultado de la ejecución de las pruebas cada vez que queramos tener feedback, cosa que habría que ir haciendo cada MUY poco tiempo. Porque cuanto antes descubramos el fallo, más fácil será corregirlo y menos impacto tendremos en el resto del sistema.
Probar te hará mejor profesional
Sin duda!! El hecho de probar tu código va a requerir que tengas que refactorizar, que simplifiques tus clases para que solo tengan el código que DEBEN tener, que en determinados escenarios aprendas cosas como mocking, la necesidad de la inyección de dependencias y la consecuente mejora en el diseño,… además SOLID, YAGNI y demás acrónimos serán parte de tu vocabulario sin que te des cuenta de ello ;)
Cómo empiezo a probar
Una vez estás convencid@ de que probar merece la pena y te ahorra tiempo, lo primero que te recomiendo es que escojas un framework de testing. Si no quieres demasiadas complicaciones al principio, utiliza el que traiga tu entorno de desarrollo por defecto. Según vayas experimentando y acostumbrándote…prueba otros. Puede que encuentres matices que te resulten más útiles en tu contexto. Lo mismo es aplicable a los mocks… cuando empieces con ellos :)
Aqui te dejo enlaces a los más utilizados aparte del que viene integrado con VS.
Testing: xunit, nunit
Y un enlace a un video (12min) en Channel 9 de mi compañero Aurelio Porras con una intro a testing en Visual Studio 2010.
Happy hacking!
~ds
PD –> Frameworks de mocks: moq, rhinomocks, moles
PD2-> Frameworks de inyección de dependencias: Unity, Ninject, Castle Windsor
PD3 –> Una herramienta interesante y relacionada es Microsoft Pex… te genera tests para tu código
PD4 –> Vamos a jugar ^^ …. piensa por un segundo que en lugar de hacer el código y luego probarlo, primero haces la prueba ideal que debería pasar el código cuando funcione… y luego haces el código que haga que la prueba funcione… bienvenido a TDD ;)