Blog de Antonio Manuel Muñiz

Desarrollo, Ingeniería y Calidad del Software

Archivos por Etiqueta: Testing

Load testing con Tsung

Tsung es una herramienta Open Source para realizar pruebas de carga de varios tipos: HTTP, WebDAV, XMPP (Jabber), PostgreSQL, MySQL y LDAP. Hasta ahora había usado JMeter para definir pruebas de carga sobre aplicaciones web, mediante la repetición controlada de peticiones HTTP más o menos complejas. Realmente lo que me ha sorprendido de Tsung es la variedad de tipos de tests posibles, especialmente las pruebas sobre bases de datos (MySQL y PostgreSQL) y sobre protocolo WebDAV.

Es cierto que la usabilidad de Tsung no está al nivel de JMeter, principalmente porque no tiene interfaz gráfica, pero el resultado en cuanto a interpretación de los reportes de la prueba, no tiene nada que envidiar, incluso diría que supera a JMeter en este aspecto.

Para realizar una prueba con Tsung el procedimiento es el siguiente (para una prueba a un servidor WebDAV, por ejemplo).

En primer lugar debemos instalar Tsung. Existen distrubuciones binarias para Debian, Ubuntu y RedHat, aunque para los amantes de la compilación existe una distribución de código fuente.

Para capturar las peticiones al servidor lanzamos el recorder:

~/Antonio$ tsung -p webdav recorder

Realizamos las peticiones configurando un proxy (localhost:8090, por defecto) en la herramienta que usemos para realizar las peticion (algún cliente WebDAV). Tsung generará un fichero XML que incrustaremos en el fichero de configuración ($HOME/.tsung/tsung.xml), en su sección sessions. En el fichero tsung.xml configuramos también los parámetros de la prueba: número de usuarios (simulados) concurrentes, intervalo entre peticiones, etc. Una caracteristica que llama la atención de Tsung es la posibilidad de configurar cierta incertidumbre en la prueba, por ejemplo, podemos indicar que simule peticiones desde un cliente X con una probabilidad del 80% y desde un cliente Y con un 20%. Incluso podemos definir incertidumbre en la propia petición (en tsung, sesiones).

Una vez configurada la prueba, lanzamos el test:

~/Antonio$ tsung -p webdav start

Al comienzo del test Tsung crea un directorio en $HOME/.tsung/log en el que escribe los ficheros de reporte. Estos ficheros serán tratados posteriormente para generar HTML con la información, esta tarea se lleva a cabo mediante el script tsung_stats.pl, incluido en la distribución de Tsung. Para poder visualizar el resultado de los tests en tiempo real podemos preparar un pequeño script que llame reiteradamente a tsung_stats.pl:

#!/bin/sh
alias tsung_stats='/usr/lib/tsung/bin/tsung_stats.pl'
tsung_stats
firefox ./graph.html
while [ "true" ]
do
  echo "Refreshing stats..."
  tsung_stats
  sleep 3
done

Este script se debe llamar desde el directorio en el que Tsung genera los reportes. Genera los HTML cada 3 segundos, lo único que debemos hacer es refrescar Firefox para ver la evolución.

tsung-graph-report

Estrategias de integración continua

Desde mi punto de vista las tareas de integración continua en un proyecto deben seguir estrategias diferentes en función del momento en que se encuentre el proyecto.

En fases tempranas del desarrollo los tests suelen fallar, porque el test no es totalmente estable, porque los desarrolladores han modificado algo que afecta a algún test, o simplemente porque en estas fases se producen cambios de rumbo más o menos importantes en cuanto a desarrollo. En esta fase temprana nos interesa que la integración continua genere reportes y documentación con una frecuencia alta (por ejemplo, cada hora) de forma que pueda consultarse el estado de las pruebas, pero que solo “avise” (fallo en una tarea) cuando falla la compilación, y no cuando fallan las pruebas. Es normal que las pruebas fallen, están para eso, si no fallaran nunca no tendrían sentido (o estamos dejando pruebas en el tintero).

Ahora bien, una vez alcanzado aproximadamente el 60% del tiempo total del proyecto se supone que la aplicación es bastante estable y las pruebas deben satisfacerse con pulcritud, ya no es aceptable que se produzcan fallos, y si se producen, debe ser motivo de alerta. En este punto la estrategia de integración continua debe cambiar, la frecuencia de ejecución de pruebas y generación de reportes puede disminuir (por ejemplo, cada noche), la compilación debe mantenerse cada hora, y si una prueba falla sí debe generarse un error en integración continua y notificarlo debidamente.

Exploratory Testing: tests al vuelo

El concepto de Exploratory Testing se adapta a la perfección al tipo de tests requeridos si se sigue una metodología ágil en el desarrollo de software.

El exploratory testing, como su nombre indica, consiste en la aplicación de un enfoque exploratorio y medianamente superficial a la definición pruebas, en contraposición al testing “profundo” o “tradicional”, que se centra en una funcionalidad y la prueba exhaustivamente mediante pesados scripts o planes de pruebas.

En concreto se trata de indentificar a grandes rasgos los principales módulos funcionales de la aplicación a probar, definiendo una serie de pruebas que no entran en detalles ni casos que se prevé que serán poco usados. De esta forma se puede definir todo un conjunto se tests que cubren gran parte de la funcionalidad básica de la aplicación.

La ventaja del exploratory testing, además de ser más ameno para el tester que el testing “profundo”, es que de una forma temprana podemos obtener un conjunto de pruebas que abarcan todo el sistema desarrollado, de esta forma se encuentran bugs de forma rápida y temprana. Este enfoque es aplicable a proyectos cuyos requisitos no son completos desde el instante 0, ya que los tests se centran en los requisitos de más alto nivel, que generalmente no cambian a lo largo del desarrollo.

Evidentemente también hay contras. El principal inconveniente es que la cobertura de código cae en picado, con el consecuente riesgo de dejar de lado problemas potenciales de la aplicación que pueden surgir en fases más tardías.

Decía al comienzo que el exploratory testing se adapta a la perfección a una metodología ágil de desarrollo de software, el enfoque es claro, podemos reducir el tiempo de definición y ejecución de pruebas, pudiendo realizar una prueba completa de la aplicación en cada iteración o hito del proyeto, podemos adaptar el plan de pruebas a los requisitos que cambien en cada hito de forma sencilla. Al ahorrar tiempo (y dinero) en las fases anteriores, el equipo de calidad puede dedicarse a preparar un buen plan de implantación lo más sencillo y automatizado posible (por ejemplo).

Como decía Aristóteles, “en el término medio esta la virtud”, por eso la realidad (al menos lo que vivo día a día) es que lo óptimo viene a ser una mezcla sutil de ambos enfoques, el pesado y el exploratorio, consiguiendo un equilibrio entre formalidad y agilidad.

Pruebas con TestNG: ordenando nuestras pruebas

TestNG es una herramienta de ejecución (y reporte de resultado) de pruebas unitarias. Esta herramienta ofrece una serie de opciones de configuración que permiten un control exhaustivo sobre la ejecución de las pruebas. En ocasiones necesitamos que las pruebas se ejecuten en un cierto orden, primero la carga de contenidos, recuperación, seguido de actualización de los mismos y por último borrado. Estas operaciones claramente requieren orden en su ejecución. JUnit, herramienta por excelencia para ejecución de pruebas unitarias, no ofrece ninguna opción al tester para mantener este orden. Vamos a ver como hacerlo con TestNG y como integrarlo en un proyecto Maven:

Configurar el pom para usar el plugin de TestNG:


<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>5.7</version>
<scope>test</scope>
<classifier>jdk15</classifier>
</dependency>

Configurar TestNG: agruparemos nuestras pruebas en grupos lógicos en el fichero testng.xml en el directorio /src/test/config.

<groups>
<define name=”root”>
<include name=”creacion” />
<include name=”recuperacion” />
<include name=”actualizacion” />
<include name=”borrado” />
</define>
<run>
<include name=”root” />
</run>
</groups>

Anotaciones en las clases de test: mediante anotaciones (Java 1.5) indicaremos a que grupos pertenece cada test y de qué grupos depende se ejecución.

@Test(groups = { "recuperacion", "root" }, dependsOnGroups = { "creacion" } )
public void recuperaEntidad1() {
...

Con esta anotación indicamos a TestNG que ejecute esta prueba despues de ejecutar todas las pruebas que pertenecen al grupo “creacion”.

Si queremos agrupar los reportes de las pruebas en un maven site podemos usar el plugin “maven-surefire-report”.
Aquí hay un pom.xml básico y un testng.xml de ejemplo.

Además del orden de las pruebas hay otros aspectos que típicamente se debe plantear un tester, como la decisión de usar una base de datos en ficheros para las pruebas o, por el contrario, usar la base de datos de desarrollo (base de datos real de la aplicación probada). Esta decisión depende en gran parte del tipo de proyecto. Si se trata de un proyecto en cuyo entorno de despliegue/producción disponemos de una base de datos contra la que podemos hacer las pruebas sin ningún tipo de restricción (tenemos permisos para hacer cualquier cosa), entonces lo mejor es hacer las pruebas contra la base de datos real, de esta forma probamos, además del funcionamiento “unitario” de nuestra aplicación, el link con la base de datos. En caso contrario, tenemos restricciones importantes sobre la base de datos, entonces ejecutaremos las pruebas sobre una base de datos en ficheros o memoria.

Una iniciativa: Testing Experience

Hace unos dos meses buscando algún tipo de publicación sobre calidad del software y testing encontré una (mas o menos bienal) sobre el el tema. Se trata de una revista (disponible en formato electrónico y en papel) llamada Testing Experience. La publicación es totalmente gratuita, una gran noticia teniendo en cuenta que cualquier libro sobre la materia no baja de los 60 Euros.

La verdad es que es bastante interesante, algunos de los temas tratados son más técnicos y otros no tanto, pero en general esta muy bien. Sobre todo hay que valorar la iniciativa de este grupo de personas al sacar a la luz una revista sobre un tema en plena efervescencia en la actualidad del mundo del software.

Me gustaría destacar en el número de este mes el artículo titulado “Turning software testing into the backbone of your quality assurance system”. El artículo expone la importancia de las pruebas en el aseguramiento de la calidad, pero indica que no lo son todo, y basar la calidad del software solo en las pruebas es un error, por supuesto comparto esta idea, hay otros muchos aspectos que componen la calidad, como aspectos relacionados con analisis estático del código fuente, la calidad de la documentación, el proceso de construcción, la automatización del despliegue, etc

Por último solo decir que aunque la revista es alemana, me ha sorprendido que su director es español, José Manuel Díaz Delgado.