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…

 

image

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:

 

image

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.

 

image

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.

 

image

 

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 😉

Publicado por

13 comentarios sobre “Si pruebas, repites – unit testing 101”

  1. Los tests no garantizan la consistencia, sino que no se cumplen ciertas inconsistencias conocidas. La demostración se puede basar en el teorema de completitud de Gödel.
    Dicho esto, el uso de los tests tiene sentido si tienes dinero para hacerlo y la naturaleza del proyecto lo precisa.

  2. @paulovila Gracias por tu comentario.
    De acuerdo con el matiz, aunque creo que es buscarle las cosquillas a un post orientado a noveles, hay muchas cosas matizables en este post 😀

    Tengo curiosidad ¿Porqué dices que solo tiene sentido si tienes dinero? No tengo una cifra de un estudio, pero en mi opinión, el tiempo (y dinero) invertido en hacer los tests merece siempre la pena. Ya sea por las inconsistencias que se evitan, por la robustez que aportan al código, por la ayuda que aportan para trazar bugs, por lo que se aprende en el proceso, etcétera…

    En cuanto al segundo comentario… personalmente creo que a todos los proyectos les vendrían bien. Y especialmente a aquellos en los que el dominio del problema sea lejano al equipo de desarrollo. Y aunque es cierto que no tienen porqué hacerse, creo que los beneficios que aportan son para cualquier proyecto.

    gracias!

  3. Gracias @Rido tienes toda la razón, he cambiado el ejemplo para intentar que sea algo más claro.

    A ver si encontramos la grabación de esa slide! y la colgamos… si no la regrabamos cuando quieras ^^

  4. Hola, efectivamente si hay un ROI al hacer Unit testing, http://collaboration.csc.ncsu.edu/laurie/Papers/TDDpaperv8.pdf http://research.microsoft.com/en-us/projects/esm/nagappan_tdd.pdf lo que viene a decir es que efectivamente si hay un ROI pero a partir de un período.
    La realidad en España ahora, (y me duele decirlo) es que las consultoras han disminuido la duración de los proyectos. Se ha pasado de 6 a 3 meses, en parte porque en proyectos más largos es más fácil fallar (aunque está por ver por qué se falla en proyectos largos) y porque los clientes no tienen suficiente dinero.
    Efectivamente, uno de los motivos por los que fallan los proyectos largos es porque no se hace TDD. ¿Entonces por qué no se hace TDD?, porque hay que invertir en formación, cosa que al empresario español le cuesta mucho, porque cree que si formas a tu equipo luego se irán a otra empresa. Simplemente nos estamos acostumbrando a la mediocridad, en parte porque al aprender tendencias nuevas (Silverlight , TDD, MVC..) estás ‘experimentando’ y no estas produciendo. Lo peor de todo es que muchas veces, si quieres hacer cosas más innovadoras y empiezas a destacar en el equipo, causas un agravio comparativo con el resto del equipo, porque sabes hacer cosas que el resto no se ha esforzado por aprender. Entonces te terminan hundiendo, o dejándote de hablar sencillamente porque les intimidas tecnológicamente.

  5. @Ibon, si no te importa te fusilaré alguno para MSDN y te cito como autor 🙂

    @paulovila Gracias 😉 pero cuidado, que aun no estamos hablando de TDD 😀 solo estamos hablando de hacer y mantener pruebas en los proyectos de desarrollo. Es una pena esa mentalidad tan extendida en las factorías de ‘good enough’. Por esos motivos, por ese miedo al cambio en las capas de management, muchas veces las pruebas, la integración contínua,el daily meeting… son acciones de guerrilla donde el equipo se pone de acuerdo y lo hace, y al de cierto periodo, el equipo de management no tiene más que estar de acuerdo, porque ya se ha cambiado y ha sido beneficioso. Hay que intentarlo! Pero cuidado con el discurso a los gerentes, hay q preparárselo muy bien… o no tenerlo! ^^ Mejor perdón que permiso, no? O:)

  6. @David: Totalmente de acuerdo en líneas generales. Además, nadie hace una evaluación real de si un proyecto le cuesta más o menos (ROI) por usar una técnica u otra, por que tendría que hacer dos veces lo mismo y comparar y eso no es factible. Cuando queremos menos tiempo de desarrollo => NECESITAMOS ALGO que nos garantice el nivel de calidad. Y esos tests son algo válido.

    @paulovila: Veo perfectamente tu punto de vista, en el aspecto social sobre todo, y entiendo bien lo que dices por que nos ha pasado a muchos: proponer innovaciones supone arrastrar a otros a aprender y eso a veces no es bien recibido.

    Respecto a tu mención a Gödel, también creo que sé por donde vas, aunque -estrictamente hablando- sus DOS teoremas no son muy aplicables a este contexto. Recordemos que Gödel resume su trabajo en 2 afirmaciones:
    1) «En cualquier formalización consistente de las matemáticas que sea lo bastante fuerte para definir el concepto de números naturales, se puede construir una afirmación que ni se puede demostrar ni se puede refutar dentro de ese sistema»
    2) «Ningún sistema consistente se puede usar para demostrarse a sí mismo»

    Como sabes, la informática utiliza subconjuntos DISCRETOS de todos los conjuntos infinitos utilizados en Matemáticas: Enteros, Naturales, Racionales, Reales, etc. Por tanto, el primer axioma no es aplicable.

    Respecto al segundo, precisamente de eso se trata: la informática no ha sido demostrada como sistema consistente (dista bastante de ello), y tampoco resulta aplicable como demostración del porqué de los fallos.

    Realmente, yo no veo el «bug» como una paradoja sino como una consecuencia inevitable de la complejidad. Afortunadamente, el usuario también empieza a comprender esto y nadie pretende que algo que lleva 120 millones de líneas de código (Windows 7) no necesite actualizaciones.

    Y nuestras aplicaciones no van a ser menos…))

    Saludos a todos

  7. @marino, q crack !! me estaba empapando de Gödel y has logrado resumir la idea principal en solo un par de párrafos, thanks !!!

    @David y @Paulovila: es una pena pero es real, el «pero» en la frase «se que las pruebas son buenas pero …» demuestra la poca falta compromiso y calidad en muchos proyectos.

    Con respecto a la formación, pues hay de 2 tipos, la que te impone tu empresa y la que uno se impone para mejorar como profesional. Personalmente, creo que este tipo de trabajo es autoformación 😀

    Salu2

  8. Una ventaja que no siempre se menciona sobre las pruebas (unitarias), que no está directamente relacionado con la calidad, es la facilidad para depurar aplicaciones en capas o componentes de manera aislada. Cuando estás programando, el hecho de saber que por ejemplo tu capa de acceso a datos está funcionando mínimamente bien, antes de codificar todo lo que va por encima, creo que te hace ir más seguro y bastante más rápido. El hecho de poder depurar estas capas, sin tener que arrancar toda la aplicación, navegar hasta la ventana en cuestión, etc, implica en muchos casos un ahorro considerable de tiempo.

Responder a dsalgado Cancelar respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *