Selección de herramientas de prueba (parte 1)

Una de las decisiones a tomar al querer hacer pruebas automatizadas es qué herramientas utilizar. Para poder tomar esta decisión resulta importante entender mínimamente la arquitectura de una infraestructura de pruebas automatizadas. El siguiente gráfico resumen de forma muy general una arquitectura de modelo para esta problemática.

arq_pruebasSi bien el gráfico puede sugerir una arquitectura de capas, la misma rara vez se cumple a nivel de implementación pero si es cierto que para elemento representa un nivel de abstracción distinto en la estructura de la solución.

En el nivel de abstracción de más alto tenemos un lenguaje de especificación que nos permite expresar la prueba.
Un ejemplo de un lenguaje posible de especificación podría ser Gherkin.

En un segundo nivel tenemos un intérprete de ese lenguaje
que nos permitirá relacionar la especificación abstracta con fragmentos de código que escribiremos nosotros y que comúnmente se denominan “glue code”.
Para el caso Gherkin tenemos como intérpretes las familia de herramientas Cucumber, en particular si quisieras escribir nuestro código en Java podríamos utilizar Cucumber-JVM.

En el tercer nivel tendremos un componente que denominamos **driver** que nos permitirá interactuar con nuestra aplicación. Lo que hace el driver en concreto es implementar el protocolo de comunicación necesario para interactuar con el sistema bajo prueba.
Siguiendo con el ejemplo anterior y asumiendo que el sistema bajo prueba es de tipo web, podríamos entonces utilizar Selenium Web Driver el ofrece una implementación en Java.

El siguiente elemento de nuestra arquitectura es la librería de aserciones, la cual nos permitirá precisamente hacer aserciones sobre el resultado de las operaciones realizadas sobre el sistema bajo prueba.
En este caso es común utilizar alguna librería de la familia xUnit. En el caso de Java utilizaríamos JUnit.

Finalmente, como último ítem de esta enumeración tenemos un motor de ejecución que se encarga de instanciar y ejecutar los elementos previamente mencionados.
En este caso una alternativa muy común en el mundo Java en particular es utilizar el mismísimo JUnit.

En la segunda parte de este artículo ofreceré algunos ejemplos concretos de implementación de esta arquitectura.

Métodos de clase

Conceptualmente los métodos de clase son métodos que tienen la particularidad de pertenecer a la clase y no a las instancias de la clase. Por esto es que para invocar a un método de clase no es necesario crear una instancia de la clase que contiene el método.

En aquellos lenguajes cuya sintaxis deriva de C, los métodos de clase se identifican con la palabra clave static y de ahí que en ocasiones se los llame métodos estáticos. Conceptualmente desde la POO creo que este nombre no es correcto pues mezcla una cuestión conceptual con un detalle de implementación de algunos lenguajes particulares.

public static doFoo() {
..
}

En Ruby, los métodos de clase de clase, se los identifica en su definición con el prefijo self.

def self.doFoo
...
end

El Smalltalk (pharo) los métodos de clase son definidos en un compartimento particular.

class_methods

Sobre el tamaño de los proyectos y los equipos en agile

Este es un tema que suele prestarse a debate cuando se habla de métodos ágiles. En diversas ocasiones he escuchado afirmaciones tales como:

Los métodos ágiles no sirven para proyectos grandes.

o

En mi equipo no podemos aplicar métodos ágiles porque somos 50 personas.

Quiero dedicar algunas líneas para desmistificar estas cuestiones.

Respecto del tamaño de los proyectos, en primer lugar debemos dejar en claro qué define el tamaño de un proyecto: ¿mucho presupuesto? ¿mucho alcance? ¿mucha gente?. Podríamos decir que el tamaño de un proyecto está dado por su alcance. Naturalmente la cantidad de personas involucradas y el presupuesto del proyecto suelen ser proporcionales al alcance del mismo.

Aclarado qué entendemos por tamaño, podemos entonces preguntarnos ¿existe alguna limitación de tamaño para aplicar métodos ágiles? La respuesta es no. Entonces ¿puedo hacer proyectos de cualquier tamaño usando métodos ágiles? Tampoco.

La cuestión pasa una vez más por el desarrollo iterativo incremental y los ciclos de feedback. En este sentido la propuesta del agilismo es particionar un proyecto grande en varios proyectos pequeños, trabajando en forma iterativa con versiones incrementales que incorporen el feedback en forma temprana.

¿Y que hay del tamaño de los equipos? La respuesta a esto se deriva del párrafo anterior, si trabajamos en proyectos chicos tendremos entonces equipos chicos. Suele  decirse que el tamaño de un equipo debe ser tal que lo puedas alimentar con dos pizzas.

Anécdotas sobre cobertura de la prueba

No quieres 100% de cobertura, porque es realmente muy caro lograrlo. En cambio deberías enfocarte en asegurarte la cobertura en los lugares donde más frecuentemente tienes bugs“.

Este es un extracto de una charla que tuve con Stef mientras transitábamos por la ruta que lleva de Lens a Lille, en Octubre de 2010. Si bien puse el texto entre comillas, la cita no es textual, pues Stef hablaba en inglés, pero la idea central es la que reflejo aquí.

Para cerrar este post, les comparto una situación que viví hace un tiempo: resulta que una de las personas que estuve capacitando hizo una demo de la aplicación que desarrolló como parte de la capacitación. La demo venia bien y en un momento le pedimos que mostrara una funcionalidad particular que no habia sido mostrada. Resulta que cuando la va a mostrar, la aplicación ¡pincha!, ja!  a lo que le pregunto ¿y los tests? adivinen….no había tests para esa funcionalidad. El porcentaje de cobertura de la aplicación no superaba el 40%. ¡Que mejor forma de ilustrar la importancia de estas cuestiones! Espero que este colega haya aprendido la lección.

Por último quiero agradecer a David Frassoni quien la semana pasada me dio la idea de escribir este post.

Algunas ideas sobre cobertura de la prueba

Ayer recibí una consulta sobre este tema y estaba convencido que ya tenia algo escrito al respecto. Me puse a buscar me encontré con este post que había escrito hace ya más de un año, pero nunca había publicado no recuerdo por qué.

Continuando con este post que hice hace un tiempo, hoy quiero compartir algunos pensamientos. Personalmente creo que es importante tener un alto grado de cobertura, pero no hay que perder de vista que la cobertura sólo indica que el código ha sido ejercitado, pero nada dice de cuan bien (o cual mal) ejercitado. Precisamente hace unos dias Carlos me compartió este artículo donde se hace especial incapié en este punto.

Como lo indica este artículo que compartí anteriormente, existen distintos tipos de cobertura. Puntualmente la forma de cobertura que yo describí entra en lo que se describe como statement coverage y que es lo que mide la gran mayoria de las herramientas.

Pero esto sólo, es una herramienta insuficiente y si uno no analiza los resultados con criterio, podria llegar a engañarse facilmente.

Es cierto que de no tener  pruebas, a tener pruebas que ejerciten el 80% del código, es una mejora muy importante, pero de ahí a “confiarnos” en la calidad de nuestro código, hay aún un trecho interesante por recorrer y posiblemente sea el trecho más complejo. Es más, dado el esfuerzo que puede implicar ese 20% restante, puede que resulte más conveniente, concentrarse simplemente en las partes del código que suelen tener acarreados más defectos.

Continuará…

User Stories vs. Casos de uso

Es común que en una primera aproximación tienda a verse las user stories como análogas a los casos de uso del Proceso Unificado, en el sentido que ambos artefactos describen en cierto modo una funcionalidad del sistema. Personalmente creo que esta analogia no es apropiada, ya que mientras un caso de uso es efectivamente una especificación de un requerimiento, la user story podría a lo sumo el título de dicho requerimiento.

Es más, en un punto podríamos decir que las user stories son en su espíritu contrarias a los casos de uso: mientras que los casos de uso pretenden contemplar los detalles del requerimiento para que el programador pueda realizar una implementación completa y correcta del requerimiento, las user stories son intencionalmente vagas pues lo que buscan es promover el diálogo entre quien debe implementar la funcionalidad y quien la ha requerido.

Continuous Delivery, una visión de alto nivel

No quiero entrar en detalle sobre definiciones, beneficios e impedimentos relacionados a esta práctica. Creo que hay suficientes fuentes de información en la web al respecto (con solo googlear el término continuous delivery encontraremos alrededor de 18.000.000 resultados).

Asumiendo que el lector ya está familiarizado con las definiciones básicas, quiero compartir mi visión de esta práctica.

Un concepto central en la práctica de continuous delivery es el denominado Deployment Pipeline. El mismo modela el proceso de la organización para materializar la implementación de una idea/necesidad del negocio. Dos puntos a destacar:

  • Hablamos de organización y no de equipo, porque este proceso involucra varios sectores de la organización más allá del equipo de desarrollo.
  • Hablamos de materializar una idea/necesidad de negocio. No basta con que el software esté desarrollado, la necesidad no se resuelve con el código dentro de un repositorio o en un paquete .zip, sino con el software corriendo en un ambiente donde pueda ser utilizado por el cliente.

La primera parte de este este Deployment Pipeline debe darlo el equipo de desarrollo con la implementación de la práctica de integración continua, lo cual puede llegar a ser un interesante desafío si el equipo trabaja sobre código legacy (entiéndase legacy=sin pruebas). Aquí es importante destacar que incorporar la práctica de integración continua va mucho más allá de poner un Build Server a monitorear el repositorio, compilar el código y ejecutar los tests.

La segunda parte del Deployment Pipeline es la que involucra a otros sectores de la organización, pues es la parte que recorre los distintos ambientes hasta llegar a producción.