Pruebas Unitarias con Jasmine: Uso de spyOn para Simular Funciones
Clase 11 de 38 • Curso de Unit Testing para MEAN con Jasmine
Contenido del curso
Creando un framework de pruebas básico
Análisis estático de código
Trabajando con Jasmine en el frontend
- 11

Pruebas Unitarias con Jasmine: Uso de spyOn para Simular Funciones
Viendo ahora - 12

Configuración de Jasmine para Pruebas de Frontend
07:48 min - 13

Configuración de Jasmine en Node.js para Pruebas Unitarias
06:18 min - 14

Pruebas Unitarias en JavaScript con Jasmine: Uso de Funciones Básicas
09:10 min - 15

Pruebas Unitarias con Jasmine: Matchers, Espías y Ciclos de Vida
04:11 min
Probando Nodejs apps con Jasmine
- 16

Pruebas Unitarias con Jasmine en Node.js y Angular
02:54 min - 17

Configuración de Pruebas Unitarias en Node.js con Jasmine
07:47 min - 18

Configuración avanzada de Jasmine y reportes en Node.js
07:00 min - 19

Implementación de Cobertura de Código con InstaBoot.js y NGC
03:29 min - 20

Pruebas Unitarias de Servidor Express con Método GET en Node.js
14:10 min - 21

Pruebas Unitarias de Código 500 en Métodos GET
04:44 min - 22

Pruebas del Método PAUSE en Desarrollo Web
12:24 min - 23

Pruebas de Métodos POST, PUT y DELETE en JavaScript Asíncrono
07:49 min
Probando Angular apps con Jasmine
- 24

Pruebas Unitarias e Integración en Angular con Jasmine
03:53 min - 25

Pruebas Unitarias de Componentes en Angular con Jasmine
09:21 min - 26

Pruebas Unitarias en Angular: Rutas y Ciclos de Vida con Jasmine
08:22 min - 27

Pruebas Unitarias en Angular: Simulación de Servicios y Componentes
12:48 min - 28

Pruebas Unitarias en Formularios Reactivos con Angular
10:48 min - 29

Pruebas Unitarias Avanzadas en Formularios Reactivos de Angular
10:03 min - 30

Pruebas Unitarias en Angular: Navegación y Outputs HTML
07:48 min - 31

Pruebas Unitarias en Angular: Testeo de Componentes y Servicios
14:56 min - 32

Pruebas Unitarias en Jasmine: Espías y Stubs en Angular
10:55 min - 33

Pruebas de Espionaje en Objetos Globales y Métodos en JavaScript
07:21 min
Pruebas de integración de Angular apps con Jasmine
- 34

Pruebas de integración con Jasmine y Angular
05:37 min - 35

Pruebas de Navegación con Angular y RouterTestingModule
06:18 min - 36

Pruebas HTTP en Angular con HTTP Client Testing Module
11:01 min - 37

Pruebas Unitarias: Cobertura Completa de Métodos HTTP en API
04:24 min - 38

Buenas prácticas de Unit Testing con Jasmine
05:46 min
Jasmine spyOn
La separación de responsabilidades es una de las buenas prácticas que encontramos en un proyecto de software. Separar responsabilidades significa agrupar código de tal manera que cada conjunto se encargue de una tarea específica.
Hablemos ahora de las pruebas unitarias. Cuando probamos un componente, queremos probar las responsabilidades que le estamos delegando al componente y no todo el código ejecutado. Es decir, si el componente A utiliza la función b(), lo que queremos probar es la lógica propia del componente y no el código de la función.
Veamos el siguiente ejemplo:
function GetMonthApi() { this.currentMonth = function () { return 'May'; } this.nextMonth = function () { return 'June' } } export function MonthCalculator() { this.api = new getMonthApi(); this.getNextMonth = function() { return this.api.nextMonth(); } this.getCurrentMonth = function() { return this.api.currentMonth(); } }
La clase MonthCalculator nos permite calcular el valor del mes actual y el siguiente. Cómo puedes ver, la función getMonthApi es utilizada dentro de la clase. Si ejecutas el set de pruebas asociadas a nuestra clase se ejecuta en Mayo el valor del siguiente mes sería Junio, o si las corres en Enero el siguiente mes sería Febrero. ¿Ves el problema?.
Si ejecutamos código que se encuentre fuera del domino de un componente, nos podemos encontrar con resultados inesperados. Es por ello, que jasmine cuenta con un sistema de espías (spyOn), cuyo objetivo principal es interceptar la ejecución de una función y simular su resultado.
Veamos un poco de código:
El primer método que vamos a probar es el de obtener el mes actual currentMonth. Si la prueba la creamos en mayo, el código debería ser:
describe('MonthCalculator', () => { it('returns the current month', () => { // Arrange const monthCalculator = new MonthCalculator(); // Act const month = monthCalculator.currentMonth(); // Assert expect(month).toBe('May'); }); });
Este código tiene un problema. La función currentMonth va a retornar un valor que depende del mes actual.
Como ya te podrás imaginar, el uso de espías resulta bastante útil en este caso debido a que podemos controlar el valor del mes retornado.
Es decir:
describe('MonthCalculator', () => { it('returns the current month', () => { // Arrange const monthCalculator = new MonthCalculator(); const spy = spyOn( monthCalculator.api, 'currentMonth' ).and.returnValue('Cristian Month'); // Act const month = monthCalculator.currentMonth(); // Assert expect(month).toBe('Cristian Month'); expect(spy).toHaveBeenCalled(); }); });
La instancia del API la tenemos almacenada en la variable this.api de nuestra clase. Jasmine nos permite interceptar el llamado a nuestro API utilizando la función spyOn. Para ello, como primer parámetro debemos pasar el objeto que contiene el método que vamos a interceptar y como segundo parámetro el nombre del mismo.
Una vez creado nuestro espía, para poder controlar el valor retornado debemos concatenar lo siguiente: .and.returnValue().
Finalmente Jasmine nos permite verificar la ejecución de la función por medio del operador .toHaveBeenCalled().
Cómo reto ve al siguiente enlace, has un fork del proyecto y realiza las pruebas relacionadas con el método nextMonth(). Recuerda crear un espía para eliminar la dependencia con nuestra API.
Finalmente, te dejo un listado de preguntas y respuestas sobre todo lo que puedes hacer con espías:
¿Cómo se crea un espía?
spyOn(obj, 'method') // obj.method es una función
¿Cómo verificar que un método fue llamado?
const ref = spyOn(obj, 'method'); expect(ref).toHaveBeenCalled(); // O directamente expect(obj.method).toHaveBeenCalled()
¿Cómo verificar que un método fue llamado con un parámetro específico?
const ref = spyOn(obj, 'method'); expect(ref).toHaveBeenCalledWith('foo', 'bar'); // O directamente expect(obj.method).toHaveBeenCalledWith('foo', 'bar')
¿Cómo puedo verificar el número exacto de ejecuciones de un método?
expect(obj.method.callCount).toBe(2)
¿Cómo espiar en un método sin modificar su comportamiento?
spyOn(obj, 'method').andCallThrough()
¿Cómo puedo cambiar el valor retornado por un método?
spyOn(obj, 'method').andReturn('value')
¿Cómo puedo sobreescribir un método?
spyOn(obj, 'method').andCallFake(() => 'this is a function');