lunes, enero 31, 2011

Niveles de felicidad en el testing

lunes, enero 31, 2011 por Martín

En la lista de Agile Spain se está comentando un artículo muy interesante de UncleBob sobre sobre Scrum y TDD y donde Leo Antoli pregunta si se están dejando de lado las capacidades de TDD como técnica para dirigir el diseño de un sistema.

Mi opinión al respecto está en el hilo y no quería entrar demasiado en ella en este artículo. Básicamente es que veo dos líneas en TDD. Una es la centrada puramente en testing, donde gira todo en torno a JUnit y tener barras verdes, y que personalmente creo que no es aplicable a diseños complejos y serios (ojo que no digo que no se haga TDD, sino sólo que en ese contexto no me parece una técnica aplicable a a dirigir nuestros diseños) ya que tiende a la sobre-simplificación de los sistemas y a un microdiseño o microtesting.

Por otra parte, tendríamos otra línea de pensamiento que apunta a TDD como una técnica de diseño en base a especificaciones y no como algo centrado puramente en testing con JUnit. Yo como modesto practicante de TDD que soy, me alineo más con esta línea de pensamiento, y donde entrarían en juego otras técnicas complementarias como BDD o los tests de rendimiento. ¿Quizás sea necesario el acuñar otro término para agrupar todas estas técnicas? No lo sé, pero se escapa de este post.

Hace poco más de un año, publicaba unas transparencias de una charla en las III Jornadas Java de alicante donde se trata algo relacionado con este tema y que también se comentó en la última reunión del grupo gallego de Agile Spain, y son los diferentes tipos de tests y el grado de felicidad que aportan. A la derecha tenéis la imagen de la transparencia relacionada. Podéis hacer clic para ampliarla.

En mi experiencia, en el desarrollo de sistemas complejos entran en juego diferentes niveles de pruebas donde cada una de ellas van aportando niveles incrementales de calidad y confianza en el sistema. Ni que decir tiene que cada nivel requiere una cobertura adecuada para que esa confianza tenga algún tipo de fundamento. En los siguientes puntos resumo básicamente los tipos de tests y lo que yo considero como sus grados de "felicidad".


  • Nivel de felicidad 1: Tests unitarios. Son los típicos tests de JUnit. Importantísimo el tenerlos. Nos dicen que nuestras clases funcionan de manera autónoma. Son tests que aportan una gran documentación y que garantizan la mantenibilidad futura de nuestro software. Ahí es nada. No es moco de pavo tener todo esto garantizado, así que para mi esta técnica es básica para cualquier programador que se quiera considerar un profesional de esto.

    Pero. Siempre hay un pero. No garantizan nada más que eso. Los tests unitarios no te garantizan que tu software funcione. Simplemente que funciona de manera autónoma. Ni siquiera garantizan que el software esté bien hecho, aunque haya sido desarrollado con TDD. Para garantizar que los diferentes subsistemas funcionan, y que lo hacen apropiadamente, habrá que integrarlos y probarlos en servidores y con recursos reales o cuasi-reales, con una simulación de actividad de usuarios lo más ajustada a la realidad. Los tests unitarios nos ofrecen mucho, pero hay que tener cuidado de esa sensación de sobreconfianza que nos pueden aportar.

  • Nivel de felicidad 2: Tests integración. Estos tests tradicionalmente incluyen acceso recursos externos como bases de datos, APIs externas, colas de mensajes, etc. e integran otros subsistemas. Se trata de comprobar como se integra nuestro software.

    Desde el punto de vista de la felicidad, aportan más felicidad que los tests unitarios (fijaros que a posta no uso la palabra valor, ya que considero que todos los tests tienen su valor). Cuando vemos que creamos tests de integración que funcionan, nuestra confianza crece y nuestra seguridad en que nuestro diseño toma forma se incrementa.

    Otro aspecto importante de estos tests es la seguridad que aportan en cuanto al funcionamiento de recursos externos. Si alguien modifica un subsistema sobre el que no tenemos control, pero disponemos de una buena cobertura de tests, los fallos de ese subsistema saldrán a la luz. De este modo detectamos fallos que son difíciles de detectar y por qué no decirlo, también nos cubrimos las espaldas respecto a grupos externos, APIs externas, proveedores externos, etc. Lo más pronto que detectemos estos errores, mejor.

  • Nivel de felicidad 3: Tests funcionales. También llamados comúnmente Tests de Aceptación. Son tests que interactuan directamente con servidores y recursos reales, lo más similares que sea posible al entorno de producción, o en algunos casos incluso a los servidores y recursos de producción para garantizar que los sistemas no se degradan o que su funcionamiento no cambia conforme al tiempo (una opción interesante en el caso de que no tengamos el siguiente nivel de tests).

    Estamos ante el mayor grado de felicidad. Estos tests realmente nos garantizan que nuestro software ¡hace lo que quiere el usuario! Una gran cobertura aquí garantiza la máxima solidez en el software desde el punto de vista del cliente. Nos garantiza poder dormir tranquilos.

    El diseño y desarrollo de test funcionales o de aceptación es algo relacionado con una técnica conocida como Behaviour Driven Development o BDD que aboga por la creación de tests en un lenguaje mucho más cercano al cliente o QA de forma que los tests puedan ser creados por no-desarrolladores. Merece la pena al respecto el echarle un vistazo a algunos de las librerías en las que ha participado su creador Dan North, como RSpec o Cucumber

  • Nivel de felicidad 3b: Tests de Rendimiento. Las pruebas de rendimiento o de stress son probablemente el tipo de pruebas más ignorados por parte de la literatura de software. En este tipo de pruebas lo que se hace es simular interacciones de usuario de manera que se incrementa el volumen y la carga de acciones se va incrementando constantemente hasta llegar al nivel requerido. Normalmente para implementar este tipo de tests se reutilizan los tests funcionales y se van incrementando progresivamente el número de tests o sesiones de usuario ejecutadas concurrentemente.

    Si nuestro sistema sobrevive a una suite lo suficientemente amplia de estos tests de stress, entonces disponemos de un software que no sólo funciona autónomamente, se integra apropiadamente y cumple los requisitos del usuario. Estamos ante un software que además es usable, no se degrada con el tiempo y cumple los niveles de respuesta y rendimiento exigidos en los diferentes SLAs (explícitos o implícitos) que se apliquen en nuestro caso.

    Curiosamente este tipo de testing no se puede decir que se prodigue demasiado dentro de la literatura, cuando paradójicamente los cambios en este área son los que pueden tener un mayor impacto en todos los ámbitos de un proyecto de software. Ejemplos comunes serían el "Hemos detectado que no podemos soportar más usuarios. Tendremos que cambiar a un modelo asíncrono.", y terminar con una rearquitectura global del sistema, o un ejemplo muy exagerado de "tenemos que migrar a un sistema NoSQL porque el modelo de BD está sobredimensionado, todo va muy lento y hacemos muchas joins. Así escalaremos mejor." que nos obligase a un cambio de modelo de datos y persistencia. Son ejemplos exagerados, que sólo pretenden destacar que el rendimiento y capacidad para asumir carga son aspectos clave en determinadas aplicaciones que conviene tenerlos medidos para que no nos coja el toro.

    Personalmente el nivel de felicidad de estos tests para mi es el máximo, aunque en la transparencia lo haya puesto al mismo nivel que el test funcional. Nuestra alegría es la de no sólo tener un software que funciona sino también la de disponer de un software que es capaz de sobrevivir a la carga de los usuarios en el tiempo sin degradarse y manteniendo niveles de calidad razonables. En definitiva, un software que no nos levantará un sábado de madrugada porque se ha caido el servidor. agile.



Y la pregunta que siempre me han hecho es, ¿entonces qué tests implemento? Mi opinión personal es que si puedes, hazlos todos. ¿Y si por la razón que sea no puedes? Bueno, entonces, si toca elegir, personalmente los tests unitarios me parecen fundamentales. TDD es importante aquí. Como digo, el hacer tests unitarios es algo básico que siempre se le debería exigir a un verdadero profesional. Por otra parte, los tests de integración son en cierto modo prescindibles siempre y cuando se disponga de tests funcionales. Yo no renunciaría a ellos, pero si es cuestión de tiempo entonces son reemplazables. Hay frameworks como Rails, Spring o Grails que hacen muy sencillo el crear tests de integración, de hecho puede ahorrarnos tiempo en comparación a hacer tests unitarios+mocks, pero ahí ya entramos en elecciones muy personales

Los tests funcionales por otra parte son de lo más importante. También son los más complejos de realizar porque en ellos influye el interfaz de usuario, que es una parte que cambia muy a menudo. Por lo tanto tienen un coste de mantenimiento importante. Esto es lo que hace que a menudo se hayan dejado de lado. Es muy común que como programadores nos conformemos con unitarios+integración y dejemos el resto como test manuales. Esto es la cruda realidad en la mayoría de proyectos. En Jobsket, por ejemplo, tengo que confesar que empezamos con todo, pero terminamos con unitarios+integración. Y por supuesto que lo hemos pagado en muchas ocasiones, pero en nuestro caso es el precio de no disponer de recursos para más. Pero ¿con recursos?, en mi experiencia los tests funcionales son fundamentales y nos devolverán el esfuerzo muy rápidamente. Lo bueno es que con BDD se están popularizando y poco a poco hacer tests funcionales es cada vez más sencillo. Los frameworks son cada vez mejores y cada vez es más fácil.

¿Y los de stress? Pues son algo deseable. No son fundamentales, pero sí son importantes. Con recursos es algo fundamental, por las razones que comentaba arriba. Los cambios en este área son de lo que impacta más en la arquitectura así que conocerlos de antemano puede ahorrar mucho tiempo.

Y bueno, no me enrollo más. Me encantaría saber vuestra opinión al respecto.

comments

0 Respuestas a "Niveles de felicidad en el testing"