Configuración de herramienta para pruebas unitarias

Configuración de herramienta para pruebas unitarias

Jasmine (JavaScript testing framework) - Wikipedia 

Tests unitarios con Jasmine

Para hacer tests unitarios en Angular se suele usar Jasmine. Jasmine es un framework Javascript (No es exclusivo de Angular, lo puedes usar en cualquier aplicación web), para la definición de tests usando un lenguaje natural entendible por todo tipo de personas.

Un test en Jasmine se ve asi:

  • describe: Define una suite de tests, es decir, una colección de tests. Ésta función recibe dos parámetros, un string con el nombre de la suite y una función donde definiremos los tests.
  • it: Define un test en particular. Recibe cómo parámetro el nombre del test y una función a ejecutar por el test.
  • expect: Lo que espera recibir el test. Es decir, con expect hacemos la comprobación del test. Si la comprobación no es cierta el test falla. En el ejemplo anterior comprobamos si true es true luego el test pasa. Cómo ves no podemos simplemente hacer la comprobación haciendo poniendo la operación ===, tenemos que usar las funciones que vienen con Jasmine, las cuales son:

    • expect(array).toContain(member);
    • expect(fn).toThrow(string);
    • expect(fn).toThrowError(string);
    • expect(instance).toBe(instance);
    • expect(mixed).toBeDefined();
    • expect(mixed).toBeFalsy();
    • expect(mixed).toBeNull();
    • expect(mixed).toBeTruthy();
    • expect(mixed).toBeUndefined();
    • expect(mixed).toEqual(mixed);
    • expect(mixed).toMatch(pattern);
    • expect(number).toBeCloseTo(number, decimalPlaces);
    • expect(number).toBeGreaterThan(number);
    • expect(number).toBeLessThan(number);
    • expect(number).toBeNaN();
    • expect(spy).toHaveBeenCalled();
    • expect(spy).toHaveBeenCalledTimes(number);
    • expect(spy).toHaveBeenCalledWith(…arguments);

Jasmine también viene con funciones que se pueden ejecutar antes de realizar un test, o después:

  • beforeAll: Se ejecuta antes de pasar todos los tests de una suite.
  • afterAll: Se ejecuta después de pasar todos los tests de una suite.
  • beforeEach: Se ejecuta antes de cada test de una suite.
  • afterEach: Se ejecuta después de cada test de una suite.
Por ejemplo:

Antes de ejecutar el test definido mediante la función it se llama a la función beforeEach la cual cambia el valor de la variable expected, haciendo que el test pase.

Tests unitarios con Angular

Si has creado el proyecto y los componentes usando Angular cli, te habrás dado cuenta de que al generar un componente, también se crea un archivo .spec.ts, y eso es porque Angular cli se encarga por nosotros de generar un archivo para testear cada uno de los componentes. Además mete en el archivo el código necesario para empezar a probar y testear los componentes. Por ejemplo, el archivo notes.component.spec.ts que se creó cuando generé un componente para crear y mostrar notas tiene esta pinta:


Lo primero que hace es crear una suite de tests para el componente con el método describe. Tras crear la suite crea dos variables que va a necesitar para testear los componentes, el propio componente, que lo mete en la variable component y una variable fixture de tipo ComponentFixture del componente, la cual sirve para tener el componente pero añadiendo más información para que sea más fácil de testear.

A contunuación llama al método beforeEach con una función asíncrona (sirve para asegurar que se termina de ejecutarla función asíncrona antes de pasar un test) para crear todas las dependencias del componente, en tese caso, el componente en sí. Si usáramos en el componente un servicio, habría que incluirlo también, creando una sección llamada providers (como en el app.module.ts).

Después vuelve a llamar a la función beforeEach, esta vez, sin ser asíncrona. Crea una instancia fixture del componente usando TestBed, el cual se encargará de inyectar las dependencias definidas anteriormente mediante configureTestingModule. Para sacar el componente en sí del fixture usa componentInstance.

Por último crea un test para comprobar que el componente se crea correctamente, para ello, llama a la función expect y espera que se cree bien y tenga error mediante toBeTruthy().

Para correr los tests y ver los resultados con Angular cli el comando es:


Testeando clases en Angular

Imaginemos que tenemos un servicio inyectado a un componente que queremos testear. Podemos usar varisas técnicas para testear el servicio:

Usando el servicio real


En este caso, a diferencia de la estructura que crea Angular cli, no estoy usando TestBed, porque por el momento no me hace falta. Simplemente creo el componente y el servicio y paso el servicio como parámetro al componente para que se inyecte mediante inyección de dependencias. Cuando hago el test, simplemente llamo al método del componente y hago la comprobación.

Esta técnica puede venir bien para aplicaciones pequeñas, pero si el componente necesita muchas dependencias puede llegar a ser muy tedioso andar creando todos los servicios. Además esto no favorece la encapsulación porque estamos creando servicios y no estamos aislando el testeo del componente.

Además de esta forma, tenemos que meter a mano en el localStorage un valor para que el authService funciona y devuelva true.

Mediante del uso de spy de Jasmine

Jasmine también ofrece la posibilidad de coger una clase y devolver directamente lo que nos interese sin tener que ejecutar internamente sus métodos:


Como ves, con la función spyOn de Jasmine podemos hacer que el servicio devuelva directamente true en la llamada a el nombre de función que le pasamos como parámetro al spy.

Testeando llamadas asíncronas

Si por ejemplo tenemos un test que testea un método asíncrono del componente o del servicio (una llamada a una API por ejemplo), podemos hacer lo siguiente:


Angular proporciona el método fakeAsync para realizar llamadas asíncronas, dejándonos acceso a la llamada a tick() el cual simula el paso del tiempo para esperar a que la llamada asíncrona se realice.

Accediendo a la vista

Para acceder a los elementos html de la vista de un componente, podemos usar su fixture:


En este caso, accedemos al botón html de la vista del componente de login mediante el debugElement del fixture, el cual nos da acceso a hacer querys de elementos html de la vista.

Como en javascript podemos acceder o cambiar las propiedades de estos elementos:


El TestBed del componente nos proporciona una manera de provocar que la vista de actualice con la nueva información en caso de que hayamos cambiado algo en el componente:


Comentarios

Entradas populares de este blog

Herramienta para el control de versiones

Herramientas para Pruebas Unitarias

Sprint review sprint2