lunes, 22 de junio de 2015

Jasmine. Introducción. Creando el primer test

Jasmine es uno de los frameworks de pruebas de código JavaScript más utilizados. Como sus propios creadores indican no depende de ninguna otra librería JavaScript y no requiere de un DOM para ejecutarse.
Este articulo pretende ser el primero de una serie en la que iré explicando desde cómo descargar el framework y crear nuestro primer test hasta cómo personalizar las características del framework o utilizar el plugin jasmine-ajax que permite simular llamadas Ajax en los tests.


Descargando Jasmine

Jasmine puede descargarse desde la página de releases del proyecto alojado en Github: https://github.com/jasmine/jasmine/releases

Si descargamos el zip de la última versión (en mi caso la 2.3.4) y abrimos el archivo comprimido no encontraremos con la siguiente estructura de ficheros y carpetas:


Si examinamos la estructura de carpetas nos encontramos con una carpeta lib que contiene a su vez la carpeta jasmine-2.3.4 que es en la que podemos encontrar los archivos que componen el framework de Jasmine.
A continuación hay dos carpetas, spec y src, que simplemente contienen ficheros de ejemplo. En la carpeta src encontramos ficheros de ejemplo de código fuente JavaScript y en la carpeta spec los ejemplos de tests para dicho código.

Más interesante resulta el fichero html SpecRunner.html que se encuentra en la carpeta raíz del paquete de descarga. Este archivo nos permite ejecutar tests y visualizar su resultado en un navegador.
Si abrimos el archivo veremos que tiene una estructura muy simple.

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Jasmine Spec Runner v2.3.4</title>

  <link rel="shortcut icon" type="image/png" href="lib/jasmine-2.3.4/jasmine_favicon.png">
  <link rel="stylesheet" href="lib/jasmine-2.3.4/jasmine.css">

  <script src="lib/jasmine-2.3.4/jasmine.js"></script>
  <script src="lib/jasmine-2.3.4/jasmine-html.js"></script>
  <script src="lib/jasmine-2.3.4/boot.js"></script>

  <!-- include source files here... -->
  <script src="src/Player.js"></script>
  <script src="src/Song.js"></script>

  <!-- include spec files here... -->
  <script src="spec/SpecHelper.js"></script>
  <script src="spec/PlayerSpec.js"></script>

</head>

<body>
</body>
</html>

En primer lugar nos encontramos con dos elementos link con referencias al favicon y a una hoja de estilos para configurar la apariencia de la página.

A continuación aparecen las referencias a los archivos del framework de Jasmine alojados en la carpeta lib.

Por último tenemos dos secciones: una primera en la que se incluyen las referencias a los archivos de código fuente cuya funcionalidad queremos testear, y una segunda en la que se referencias los archivos con la definición de los tests.

Si abrimos el archivo con un navegador (al abrirlo desde el sistema de archivos es posible que nos aparezca un mensaje de seguridad pidiendo autorización para ejecutar su contenido) veremos un resultado similar a este:

Aspecto SpecRunner.html

La pantalla nos indica que se han ejecutado 5 tests (specs) y todos con éxito (0 failures).
Debajo aparecen la descripción de los tests. Cada uno de los 5 tests se corresponde con una de las líneas color verde, precisamente el hecho de que aparezcan en color verde indica que el test se ha ejecutado con éxito.

Hola Mundo


Ya hemos ejecutado los primeros tests, aunque fueran los tests de prueba, lo cual quiere decir que disponemos de todo lo necesario para testear nuestras fuentes.

Para poder crear el primer ejemplo lo que voy a hacer es crear un nuevo sitio web con mi aplicación de desarrollo web (existen muchas y muy buenas, y cada cual tiene su favorita, así que cada uno utilice la que desee).

En el sitio web me crearé una carpeta scripts que albergará el código fuente y otra carpeta test en la que incluiré el framework de Jasmine y los archivos con los tests. De esta forma cuando despliegue el sitio web a un entorno de producción, en el que en principio no nos interesa tener el código de testeo, simplemente tendré que evitar copiar esta carpeta test.

En la carpeta test voy a copiar el fichero SpecRunner.html y crearé dos nuevas carpetas: lib en la que copiaré los archivos del framework de Jasmine (los contenidos en la carpeta lib/jasmine-2.3.4 del paquete de descarga) y spec en la que iré creando los archivos de tests.

Como he modificado la estructura de las carpetas del framework, y no me interesa mantener los tests de prueba, voy a editar el archivo SpecRunner.html para actualizar las referencias al framework y eliminar las de los archivos de prueba.

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Jasmine Spec Runner v2.3.4</title>

  <link rel="shortcut icon" type="image/png" href="lib/jasmine_favicon.png">
  <link rel="stylesheet" href="lib/jasmine.css">

  <script src="lib/jasmine.js"></script>
  <script src="lib/jasmine-html.js"></script>
  <script src="lib/boot.js"></script>

  <!-- include source files here... -->

  <!-- include spec files here... -->

</head>
<body>
</body>
</html>

Si cargamos la página SpecRunner.html en un navegador veremos que nos aparece un mensaje indicando que no se ha encontrado ningún test(spec).

SpecRunner sin tests

Lo primero que necesitamos para crear nuestro primer test es un código que testear, así que voy a crearme en la carpeta scripts un fichero HolaMundo.js con una función que simplemente devuelva ese mensaje "Hola Mundo".

function holaMundo() {
    return "Hola Mundo";
}

En la carpeta spec voy a crear un fichero HolaMundo.specs.js en el que crearé los tests para comprobar que el código de la función funciona correctamente (como no sea así no vuelvo a escribir un artículo en mi vida....).

Lo primero que debemos hacer al escribir los tests es definir un conjunto de tests(suite) a través del método describe.
En muchas ocasiones utilizaré la nomenclatura en inglés, y más concretamente la utilizada en la documentación de Jasmine, o la añadiré entre paréntesis como hasta ahora (spec, suite, expectation,...). El motivo es que es importante estar familiarizado con esta nomenclatura, tanto porque es la que utilizan los mensajes del framework como por ser la utiizada en la mayoría de la documentación que se puede encontrar en internet.

El método describe acepta dos parámetros, una cadena que define el conjunto de tests(suite) y una función. La función es un bloque de código que ejecuta los tests.

describe("Hola Mundo", function(){

});

Dentro del cuerpo de la función de la suite deberemos definir los diferentes tests(specs). Cada test(spec) se define a través del método it que recibe los mismos parámetros que el método describe: una cadena con la descripción del test y una función que implementa la lógica del test(spec) y comprueba el resultado obtenido.

Voy a definir algunos tests(specs) para la función holaMundo:

describe("Hola Mundo", function(){

 var msg = holaMundo();

 it("El mensaje no debe estar vacío", function () {

 })

 it("El mensaje debe ser \"Hola Mundo\"", function () {

 });

});

En el cuerpo de la suite, en primer lugar realizo una llamada a la función holaMundo y almaceno el resultado en una variable. A continuación se deberán ejecutar los tests(specs) que comprueban que el resultado de la función es correcto. Nuestro primer test(spec) comprobará que el mensaje devuelto por la función no esté vacío, el segundo comprobará que se corresponda con el resultado esperado: una cadena "Hola Mundo".

En el cuerpo de la función de cada test(spec) se implementa el código para ejecutar el test y una serie de "expectativas"(expectations). Estas "expectativas"(expectations) se definen a través del método expect que recibe como parámetro el valor a evaluar. El resultado de este método se encadena a un método de comprobación(matcher) que devuelve un valor booleano que indica si la comprobación se ha superado con éxito.

Un ejemplo de estas comprobaciones(expectations) sería:

expect(value).toBe(4);

Que vendría a indicar que se espera(expect) que el valor de la variable value sea(toBe) igual a 4. toBe sería el método de comprobación(matcher) que devuelve un valor booleano indicando si se cumple la "expectativa"(expectation).
Cualquier método de comprobación(matcher) puede convertirse en una comprobación negativa encadenando not antes del método de comprobación(matcher).
Por ejemplo:

expect(value).not.toBe(4);

Indicaría que se espera(expect) que el valor de la variable value no(not) sea(toBe) igual a 4.

Entonces únicamente nos faltaría incluir algunos métodos expect en nuestros tests:

describe("Hola Mundo", function(){

 var msg = holaMundo();

 it("El mensaje no debe estar vacío", function () {
  expect(msg).not.toBe(null);
  expect(msg).not.toBe("");
 })

 it("El mensaje debe ser \"Hola Mundo\"", function () {
  expect(msg).toBe("Hola Mundo");
 });

});

En el primer test ("El mensaje no debe estar vacío"), comprobamos que el valor msg devuelto por la función holaMundo no sea nulo ni una cadena vacía.
En el segundo test comprobamos que este valor se corresponda con el literal "Hola Mundo".

Ya tenemos completamente definidos los tests para nuestro código. Ahora para poder evaluar los tests desde la página SpecRunner.html deberemos incluir las referencias al archivo de código fuente y al de la definición de los tests.

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Jasmine Spec Runner v2.3.4</title>

  <link rel="shortcut icon" type="image/png" href="lib/jasmine_favicon.png">
  <link rel="stylesheet" href="lib/jasmine.css">

  <script src="lib/jasmine.js"></script>
  <script src="lib/jasmine-html.js"></script>
  <script src="lib/boot.js"></script>

  <!-- include source files here... -->
  <script src="../scripts/HolaMundo.js"></script>

  <!-- include spec files here... -->
  <script src="spec/HolaMundo.specs.js"></script>

</head>
<body>
</body>
</html>

Si volvemos a cargar la página en el navegador obtendremos el resultado de ejecutar los tests.

Tests HolaMundo ejecutados correctamente

Ahora podemos modificar la función holaMundo para devolver un mensaje diferente y comprobar que el resultado de ejecutar los tests:

function holaMundo() {
    return "Hola Asier";
}

Al volver a cargar la página SpecRunner.html obtendremos el siguiente resultado.

Fallo en test HolaMundo

Nos indica que se han ejecutado 2 tests(2 specs) pero que uno de ellos ha fallado (1 failure).
El siguiente mensaje indica el test(spec) que ha fallado: Hola Mundo(descripción del conjunto de tests o suite) El Mensaje debe ser "Hola Mundo"(descripción del test o spec)
Y a continuación aparece el error detectado: Expected 'Hola Asier' to be 'Hola Mundo' (se esperaba que 'Hola Asier' fuera 'Hola Mundo'), y el volcado de la pila.

Si pulsamos en el link de la lista de tests(Spec list) veremos la lista de tests(specs) ejecutados, apareciendo en verde los que se han ejecutado correctamente y en rojo aquellos en los que ha fallado alguna comprobación (expectation).

Lista tests ejecutados

Del mismo modo, pulsando sobre el test que ha fallado o sobre el link fallos(Failures) volvemos a la información detallada del error.

No hay comentarios:

Publicar un comentario