La pequeña gran guía sobre Load Tests

Las pruebas de carga se usan para observar y analizar un sistema en unas circunstancias específicas. Por ejemplo, podríamos crear un portal web en el que esperamos un número determinado de usuarios. Y antes de ponerlo en producción queremos estar seguros de que se va a comportar correctamente cuando lleguemos al cupo esperado. La idea es montar un entorno de pruebas que simule estas condiciones y así monitorizar los servidores implicados, en busca de unas estadísticas. El resultado de ejecutar este tipo de prueba es una gran cantidad de datos que nos informarán de si el sistema se ha comportado como esperábamos y qué cuellos de botella se han encontrado.

Hay que tener cuidado y no confundir las pruebas de estrés con pruebas de carga. Las de estrés tratan de llevar al límite un sistema, para poder observar si tiene estabilidad en condiciones difíciles y encontrar cual es el máximo que le podemos pedir antes de que empiece a fallar. Mientras que las de carga, aunque son muy parecidas y de una se puede sacar la otra cambiando unos parámetros de la configuración, no buscan llegar al límite. Solo observar el comportamiento en unas condiciones normales/esperadas.

A lo largo de este artículo vamos a tratar varios temas, y puede ser que resulte algo denso. La intención no es explicar todos los detalles de este tipo de pruebas, ya que sería una labor titánica. Simplemente mostraremos las actuaciones típicas que solemos realizar en nuestros proyectos:

 

Entorno de test

Antes de empezar a trabajar tenemos que tener licencias e imágenes de dvd de Visual Studio Ultimate y los Visual Studio Agents. Todo este software se puede encontrar en una cuenta de MSDN con licencia Ultimate. Los test de carga no pueden ser ejecutados desde un Visual Studio de licencia inferior, simplemente no tendrá las opciones.

La idea de todo entorno para este tipo de pruebas es usar:

Entorno de pruebas

Para tener este entorno se recomienda bien crear una serie de máquinas virtuales en azure o bien físicamente poseer estos equipos e instarles el software de Visual Studio Test Agent o Test Controller según corresponda.

controller-config

En la configuración del controlador se nos solicitará la cuenta que va a ejecutar el servicio, opcionalmente si queremos registrar el controlador en un TFS (para ejecutar las pruebas desde ahí) y por último, un servidor de base de datos donde almacenar los resultados.

agent-config

En cuanto a los agentes, después de preguntar si deseamos ejecutar el agente como un proceso interactivo o como un servicio (recomendamos esta última), deberemos especificar la cuenta encargada de ejecutar el servicio y cuál es el equipo que tiene instalado el controlador.

En la nueva versión de Visual Studio 2013 no tendremos la obligación de crear este entorno, ya que los tests de carga se podrán ejecutar directamente en el TFService (azure):

vs2013-tfs-controller

Bastará con configurar un archivo de Test Settings y especificarlo. Luego en el Team Explorer habrá que conectarse con una cuenta de TFService (TFS en la nube) y ya se ejecutarán allí automáticamente.

Para terminar con las configuraciones a parte de esto, también tendremos que desplegar nuestro aplicativo de tal forma que sea accesible por el entorno que hemos creado. Pero esto ya depende de cada uno…

Volver al índice  

Creando un test de web performance

Un test de carga está compuesto por un conjunto de juegos de prueba que pueden ser de todo tipo. Pero en el caso de querer probar una aplicación web, lo más recomendable es generar ese juego de pruebas que vamos a ejecutar en formato de Web Performance Tests.

Un Web Performance Test está compuesto por una serie peticiones web, dentro de estas peticiones podemos especificar varias propiedades. Además podemos crear unas reglas para extraer datos que vienen en la respuesta y unos validadores que nos ayudarán a saber si el resultado de esa petición es el esperado.

Para crear un Web Performance Test vamos a necesitar tener primero un proyecto de tipo de load test abierto. Entonces a este proyecto le añadimos un nuevo elemento de tipo Web Permormance Test y se nos abrirá una ventana de Internet Explorer con el plugin Web Test Recorder a mano izquierda:

web-test-recorder-1

Nuestra misión ahora será ir ejecutando un caso de prueba desde nuestra web. Por ejemplo puede ser realizar una búsqueda:

web-test-recorder-2

Una vez hayamos terminado presionamos en el botón de Stop. Entonces volverá a aparecer en primer plano el Visual Studio con las request capturadas dentro de nuestro test. Ahí el sistema analizará las relaciones entre las peticiones. Es decir, que si por ejemplo un input de tipo hidden tiene un valor que se pasa en un post de un formulario, hacerlo dinámicamente, sin que nosotros tengamos que especificarlo. Una vez haya realizado estas comprobaciones tendremos algo como esto:

web-test-1

Aquí vemos que hemos realizado dos peticiones, una a la página principal y otra que es la búsqueda, que contiene una serie de datos en forma de parámetros. Una de las primeras acciones que es recomendable hacer es parametrizar los servidores web, presionando el segundo botón del ratón y seleccionando la opción de Parameterize Web Servers. Aquí nos propondrá una variable de contexto con nuestro nombre de servidor. Así si cambiamos de entorno, solo tenemos que modificar el valor de este parámetro.

web-test-2

Ahora veremos que opciones tenemos de configuración por cada petición. Si marcamos la primera por ejemplo, en la ventana de propiedades encontraremos algo parecido a esto:

web-test-3

Aquí podremos modificar todos los datos de la request, como por ejemplo si vamos a usar Caché (nos puede interesar o no en este tipo de pruebas), si esperamos un código HTTP de respuesta concreto o el Think Time. Este último es importante ya que nos ayudará a imitar el comportamiento de un usuario de verdad. El Think Time es el tiempo que se añade después de esta request, en el que simulamos que un usuario puede tardar en leer, hacer clic o escribir algo en pantalla. Su valor equivale a la cantidad de segundos que se esperará para ejecutar la siguiente petición web.

Si pulsamos con el segundo botón del ratón sobre una de las peticiones aparecerán ante nosotros un buen número de opciones:

web-test-4

Las primeras opciones están relacionadas con la prueba y las demás con la petición seleccionada. A nivel de prueba podremos:

Con respecto a las opciones referentes a la petición seleccionada encontraremos:

Como hemos dicho antes, un Web Performance Test posee un contexto de ejecución que es común para todas las peticiones que contiene. En este contexto podemos crear y borrar datos para ponerlos a disposición de ciertas peticiones que lo necesiten. Para hacer uso de estas variables de contexto se ha creado un sistema “plantillado” para poner valor a los parámetros (uri, headers, querystring o form body). Consiste en usar el mismo nombre con el que hemos guardado el dato entre dos llaves: . El ejemplo más claro de esto lo veremos en nuestro test, al parametrizar el servidor web, que ha cambiado todas las URI de las peticiones para que contengan “” en lugar del nombre del servidor.

Para cambiar los valores y sustituirlos por parámetros, tendremos que seleccionar uno de ellos y en la ventana de propiedades veremos esta serie de opciones:

web-test-5

Como vemos en la captura, podremos cambiar el valor por uno de los parámetros contextuales, o incluso añadir una fuente de datos como podría ser un Excel o un XML, de donde podremos recogerlos. Si el parámetro que queremos usar no se encuentra en el listado, podremos escribir el literal con las llaves.

Una vez que tenemos el test a nuestro gusto, podremos ejecutarlo y en los resultados observaremos todo lo que ha ido pasando.

web-test-6

Si observamos detenidamente los detalles, veremos que no solo ha cargado las requests que le hemos definido, si no que se ha ido operando como un navegador de internet: descargando el contenido dependiente y respondiendo de la forma correcta cuando se encuentre escenarios que lo requieran.

Volver al índice  

Custom extraction rules and validators

Aunque existen ya de por si muchas reglas de extracción y validación; puede ser que estas no se ciñan a nuestras necesidades específicas. Aunque antes de desarrollar una nueva recomendamos echar un vistazo a todas las opciones, ya que incluso existe una norma de extracción genérica donde podemos introducir una expresión regular.

Para crear una regla de extracción simplemente heredaremos de la clase base “ExtractionRule”, añadiremos unos decoradores de descripción y nombre, para que se muestre en los diálogos de configuración de una forma correcta, y sobrescribiremos la función de “Extract”:

[Description("This is a demo extraction rule")]
[DisplayName("My Custom Extraction Rule")]
public class CustomExtractionRule : ExtractionRule
{
    public override void Extract(object sender, ExtractionEventArgs e)
    {
        var bodyText = e.Response.BodyString;
        // search something ...
        e.WebTest.Context[this.ContextParameterName] = found;
    }
}

Lo que tendremos que hacer en el método de extracción será recoger un dato de la respuesta del servidor y añadirlo al contexto para que esté disponible para otras pruebas venideras. Es simple, pero a la vez podemos complicarlo todo lo que queramos.

En cuanto a las reglas de validación, funcionan con la misma dinámica, con la diferencia de que heredaremos de la clase “ValidationRule” y el método que sobrescribiremos será “Validate”:

[Description("This is a demo validation rule")]
[DisplayName("My Custom Validation Rule")]
public class CustomValidationRule : ValidationRule
{
    public override void Validate(object sender, ValidationEventArgs e)
    {
        var bodyText = e.Response.BodyString;
        // validate something
        e.IsValid = result;
        e.Message = result ? "Ok" : "Something went wrong";
    }
}

Una vez hayamos validado la información que nos interesa, indicaremos los resultados en los argumentos de la función. Si la regla de validación responde como que no es válido, la prueba que se está ejecutando en ese momento, será fallida.

Volver al índice  

Configurando el test de carga

Una vez hemos creado un buen juego de pruebas web, concretamente las que consideramos que van a realizar los usuarios en el sistema, ya podemos definir una prueba de carga.

Para esto, añadiremos a la solución un nuevo Load Test. Al hacerlo aparecerá una ventana tipo Wizard, que nos guiará en el proceso de definición de la prueba.

load-test-1

En la primera pestaña relevante tendremos que dar un nombre a un escenario. Un Load Test puede contener más de un escenario. Y un escenario no es más que un contexto de ejecución con sus normas y comportamientos correspondientes.

También tendremos que decidir el perfil para cálculos de Think Time. Esto es el tiempo de espera entre peticiones, un valor que ya asignamos a la hora de crear los Web Permormance Tests. Se nos propondrá usar el valor que ya tenemos grabado, usar una distribución normal según el valor que grabamos (+-20%) o no usar Think Times.

Y por último podremos especificar el Think Time entre cada una de las iteraciones de la propia prueba de carga.

load-test-2

En las siguientes páginas seguiremos definiendo las características de escenario. En la segunda tendremos que señalar la forma en la que queremos simular los diferentes usuarios del sistema y su número. Tendremos la opción de que un número constante de usuarios esté conectado o bien hacer una carga progresiva, esperando con un número inferior que se va incrementando hasta un punto determinado con el tiempo.

Aunque la página que nos tocaría ahora sería la de Text Mix Model, personalmente prefiero antes visitar la de Text Mix, donde definiremos las pruebas que cada usuario va a lanzar:

load-test-4

Básicamente tendremos que ir añadiendo o borrando Web Performance Test a la lista y distribuirlos de la forma que nos parezca más correcta. Por ejemplo, si un usuario realiza una búsqueda, podríamos pensar que lo normal sería que visitara los resultados de esa búsqueda, antes que realizar una nueva. Por lo que si hacemos dos pruebas web para estas actividades, la correspondiente a la búsqueda tendrá un porcentaje menor, para que se ejecute menos veces.

Como nota, si queremos añadir una prueba y vemos que no está en el listado que se nos propone, quizá es que primero tengamos que compilar la solución. Entonces al intentarlo de nuevo veremos que ahora si aparece.

load-test-3

Volviendo atrás a la página de Test Mix Model, lo que vamos a tener que decidir es cómo queremos que los usuarios simulados vayan ejecutando las pruebas definidas en el Test Mix:

Aquí no hay ninguna recomendación, cada uno tendremos que decidir cual se ajusta mejor al escenario que queremos definir.

load-test-5

En la siguiente pantalla se nos permitirá definir el Network Mix. Esto no es más que el porcentaje de conexiones que vendrán de los diferentes tipos de redes. Por defecto Visual Studio tiene definidos unos cuantos, pero si quisiéramos crear un tipo de red que sea diferente tenemos aquí un artículo que nos puede ayudar mucho:

http://blogs.msdn.com/b/rubel/archive/2011/06/05/load-test-how-to-create-a-custom-network-profile-for-network-emulation.aspx

load-test-6

La última característica que vamos a definir del escenario es el Browser Mix. Porque podría ser que tuviéramos un comportamiento en la página web diferente en dependencia del navegador, como por ejemplo si te conectas desde un dispositivo móvil. Aquí lo más recomendable es ser consecuente con el escenario donde se va a distribuir nuestra aplicación. No es lo mismo ponerla en una zona pública, donde tendremos que dejarnos guiar por las estadísticas normales de internet; que en la intranet de la empresa donde solo dejan usar Internet Explorer 8.

load-test-7

Cuando ya hemos terminado de definir el escenario tocará el turno de añadir los servidores que ejecutan la aplicación y los contadores de los mismos que queremos observar. Por ejemplo, si tenemos un servidor de base de datos, añadiremos su nombre host y solo marcaremos los contadores de SQL.

Una nota aquí es que los servicios remotos de logs y alertas de performance tendrán que estar iniciados en la máquina servidora para poder recoger estos datos.

load-test-8

La última página del Wizard será la que defina los datos correspondientes a la ejecución de la prueba de carga:

Una vez hayamos finalizado el proceso se nos abrirá una ventana con los detalles de la prueba de carga:

load-test-9

Seleccionando cada componente y mirando en la ventana de propiedades podremos cambiar toda la configuración que hemos creado en el Wizard. Además presionando con el segundo botón del ratón podremos entrar en ventanas similares a las que usamos durante la creación del Load Test.

Aquí habrá dos puntos en los que habrá que detenerse a mirar, ya que nos aporta ciertas opciones extras que anteriormente no hemos tenido la posibilidad de configurar.

Si pulsamos sobre Run Settings, el que esté activo, en la ventana de propiedades veremos muchas más opciones de las que definimos. Cosas como gestión de errores o guardar logs de ejecución (no solo cuando fallen), hasta el cool-down time, que no es más que un tiempo que se espera a que las pruebas paren, para dar tiempo al sistema a estabilizarse después de una ejecución.

Y por último si tuviéramos un escenario en el que el usuario realiza una actividad antes de empezar con todas las pruebas (como por ejemplo un login) y/o otra para terminarlas (como por ejemplo un logout), podremos crear un Web Permormance Test para realizar estas actividades y añadirlo al inicio o al final de toda la duración de la prueba.

Para ello tendremos que con el segundo botón del ratón pulsar sobre Text Mix. Allí seleccionaremos la opción de Edit Test Mix. En la nueva pantalla que aparecerá veremos en la parte inferior unas opciones de añadir una prueba que se inicia antes que el resto de pruebas sean ejecutadas, una vez para cada usuario y otra para la de después:

load-test-10

Aquí podremos marcar la casilla y seleccionar la prueba que se dedica a esa actividad.

Volver al índice  

Ejecutando y explotando los resultados

Antes de ejecutar nuestras pruebas de carga tendremos que configurar los Test Settings. En todo proyecto de pruebas de carga tiene que haber a nivel de solución un archivo de configuración de la prueba, podríamos crear uno nuevo si no existe o varios diferentes para poder ejecutar las pruebas en diferentes entornos.

test-settings-1

Al hacer doble clic en un archivo de Test Settings nos aparecerá una nueva ventana donde podemos configurar la ejecución de las pruebas:

vs2013-tfs-controller

En la primera página encontraremos la descripción de la configuración y podremos decidir, solo si estamos en VS2013, si queremos ejecutarlos en un controlador local o usando el de Team Foundation.

Si elegimos ejecutar las pruebas en una máquina local o un Test Controller, aparecerán nuevas opciones. Una de las más significativas es la de Roles:

test-settings-2

Aquí tendremos que especificar si queremos usar el propio Visual Studio local o una máquina remota que es el controlador. Si marcamos esta última, tendremos que indicar el host del controller.

Otra página en la que podríamos tener que configurar algo especial, es la de Deployment. Cuando nuestras pruebas necesiten referencias a ensamblados que no son el propio ensamblado de la prueba, tendremos que añadir estos ensamblados en como elementos que hay que desplegar junto con la propia prueba. Un ejemplo de esto podría ser un ensamblado donde guardamos normas de extracción y validación que usamos en los tests.

El resto de opciones como los diagnósticos y demás, podemos dejarlos con los valores por defecto, en un principio. Para terminar con la configuración previa en el menú de Load Test de Visual Studio tendremos que activar la configuración que queramos usar:

test-settings-3

Ahora bastará con abrir la prueba de carga y presionar el botón de ejecución de las pruebas de carga. Visual Studio se conectará con el controlador que hemos especificado y este orquestará esta ejecución enviándonos datos de diagnóstico en tiempo real, que podremos ver desde el propio Visual Studio.

test-execution

Aquí podremos ver gráficas estándar o crear las nuestras propias seleccionando contadores que vemos a mano izquierda. También tendremos unas tablas a modo resumen. Así que solo nos quedará esperar a que nuestra prueba de carga termine.

Una vez terminen las pruebas podremos ver el resultado completo que el controlador almacenará en la base de datos que indicamos.

test-results

Tanto en las gráficas como en las tablas podremos ver si hay algún contador extraño que ha ido demasiado arriba, si por ejemplo vemos que no se libera bien la memoria de la aplicación, o simplemente si los tiempos de respuesta son los que esperábamos.

Otro detalle que nos puede ayudar a luego diferenciar las pruebas que hemos ido lanzando es añadir una descripción. Para ello tendremos que pulsar en el icono señalado y en el campo descripción añadir un comentario. Después al buscar resultados de la ejecución de esta prueba, encontraremos este campo de descripción que nos ayudará a identificarla:

test-results-description

Por último, para acceder a estos resultados, tendremos que abrir el archivo del test de carga y en el menú contextual seleccionar la opción de abrir resultados de tests:

test-results-open

Volver al índice  

PAL: Performance Analysis Logs

PAL (https://pal.codeplex.com/) es una herramienta desarrollado por Clint Huffman, con la ayuda de Microsoft, que realiza un análisis de los contadores de rendimiento del sistema, en busca de los thresholds conocidos.

Básicamente nos ayudará a crear unos contadores que podremos activar en los servidores de nuestra aplicación y luego los analizará y nos devolverá un documento con gráficas y umbrales que nos harán la vida más fácil.

Para usarlo solo tendremos que ir a la página web del proyecto, descargarlo e instalarlo. Y entonces nos tendremos que plantear qué datos y de qué servidores queremos recolectar.

Lo primero que haremos es generar los contadores, para eso abriremos PAL y en la página de Threshold File, encontraremos en un combobox varias plantillas ya creadas. Generalmente suelo usar la de SQL Server y la IIS. La idea es exportar estas plantillas para luego llevarlas a nuestros servidores y activar esos contadores:

pal-1

Ahora recogeremos el archivo xml resultante y lo llevaremos a nuestro servidor. Dentro del servidor abriremos el Performance Monitor:

pal-2

En Data Collector Sets tendremos que crear uno nuevo, al presionar en la opción se nos abrirá un nuevo dialogo, donde le daremos un nombre y le indicaremos que queremos basar el contador en una plantilla:

pal-3

En la siguiente página tendremos que presionar sobre “browse” y buscar el archivo que exportamos del PAL.

pal-4

Ahora ya podemos finalizar el Wizard.

Cada vez que vayamos a ejecutar una prueba de carga, solo tendremos que ir al servidor, al Performance Monitor y activar el contador que hemos creado. Cuando la prueba termine lo pararemos e iremos a buscar los resultados a la ruta por defecto: “c:\PerfLogs\Admin[Nombre del contador]”.

pal-5

Una vez ha terminado deberíamos encontrarnos con una serie de archivos parecida a esta:

pal-6

Para obtener nuestro informe tendremos que abrir PAL de nuevo e indicarle que este es nuestro documento de entrada:

pal-7

En la página de Counter Log seleccionaremos el archivo.

pal-1

En Thershold File tendremos que volver a seleccionar el perfil que hemos tratado.

pal-8

Una vez termine se abrirá una nueva ventana del explorador de internet con un informe muy completo sobre nuestro sistema. Y es muy recomendable leerlo entero en busca de los posibles problemas que se han podido encontrar en el sistema.

Volver al índice  

Conclusiones

A lo largo de este artículo hemos visto una pequeña parte de la creación y explotación de datos en pruebas de carga. Pero este contenido no es todo. Han quedado muchas cosas en el tintero que nos pueden ser útiles en nuestros proyectos. No obstante, esperamos haber podido ayudar a esas personas que no saben cómo realizar este tipo de pruebas. Y a los que ya las conocían de sobra, a encontrar un lugar donde consultar y reforzar ideas.