Contenido del curso
Escribiendo pruebas
Pruebas Unitarias
Integration Test & E2E
UI Test
Automatizar
Spies
Contenido del curso
Spies
Andrés Pérez Díaz
EstudianteDavid Antonio Garcia Saaib
EstudianteDiego Vergara
EstudianteMiguel Angel Reyes Moreno
EstudianteRubén Ernesto Aragón Gil
EstudianteAram Missael Guzmán Boiso
EstudianteDiego Fernando Velesaca Orellana
EstudianteEDISSON MOGOLLON
EstudianteNicolas Molina
Profesorjefred bedoya
EstudianteZaidibeth Ramos
EstudianteJesus David Mejia
EstudianteJesus David Mejia
EstudianteJesus David Mejia
EstudianteJesus David Mejia
EstudianteDany Ruddy Huayhua Huayhua
EstudianteMuy interesante este curso, no entiendo por qué no tiene más visualizaciones.
const fakeBooks = [ { _id: 1, name: 'Harry Potter' }, { _id: 2, name: 'Harry Potter 2' }, { _id: 3, name: 'Harry Potter 3' }, ];
const mockGetAll = jest.fn(); Es una funcion fantasma que manejaremos.
jest.mock('../lib/mongo.lib', () => jest.fn().mockImplementation(() => ({ getAll: mockGetAll, create: () => { }, })));
jest.mock('../lib/mongo.lib' Suplanta a la llamada de la libreria de mongo, para que cuando sea llamada en su lugar ejecute otro jest.fn(), y mediante mockImplementation sea seteado el objeto con el metodo getAll: mockGetAll.
beforeEach
let service; beforeEach(() => { service = new BooksService(); });
service = new BooksService() crea una instancia de BookService, que ya contiene la trampa que al llamar a mongo, lo suplanta con los metodos getAll y create.
Test
mockGetAll.mockResolvedValue([...fakeBooks]) const books = await service.getBooks({}) expect(books.length).toEqual(3); expect(mockGetAll).toHaveBeenCalled() expect(mockGetAll).toHaveBeenCalledWith('books', {}) expect(mockGetAll).toHaveBeenCalledTimes(1)
Seteamos que cuando mockGetAll sea llamado retorne fakeBooks.
service.getBooks({}) hace una llamada al servicio.
Los expect son en si ifs que ven el detalle de la data.
expect(books.length).toEqual(3) verifica que la respuesta tenga tres posiciones.
expect(mockGetAll).toHaveBeenCalled() Verifica que haya sido llamada esta funcion fake.
... y asi xD
Buena explicación bro 👍
Este comentario lo había hecho antes pero lo vuelvo a hacer por si alguien se le pasó:
Para evitar errores de typo con Jest y que VS Code pueda autocompletar código de Jest, instalen esta dependencia de npm:
npm i @types/jest -D
Así me evité el error que tuvo el profe Nico :D
const BooksService = require('./books.service'); const fakeBooks = [ { _id: 1, name: 'Harry Potter', }, ]; const mockGetAll = jest.fn(); jest.mock('../lib/mongo.lib', () => jest.fn().mockImplementation(() => ({ getAll: mockGetAll, create: () => {}, }))); describe('Test for BooksService', () => { let service; beforeEach(() => { service = new BooksService(); jest.clearAllMocks(); }); describe('test for getBooks', () => { test('should return a list book', async () => { // Arrange mockGetAll.mockResolvedValue(fakeBooks); // Act const books = await service.getBooks({}); console.log(books); // Assert expect(books.length).toEqual(1); expect(mockGetAll).toHaveBeenCalled(); expect(mockGetAll).toHaveBeenCalledTimes(1); expect(mockGetAll).toHaveBeenCalledWith('books', {}); }); test('should return a list book', async () => { mockGetAll.mockResolvedValue([{ _id: 1, name: 'Harry putter 2', }]); const books = await service.getBooks({}); console.log(books); expect(books[0].name).toEqual('Harry putter 2'); }); }); });
Spies
Los spies son muy utiles para realizar pruebas de caja blanca.
Para este ejemplo se va espiar el comportamiento de le método getAll .
Para realizar esto debemos crear una variable y asignarla a una función de jest.
const mockGetAll = jest.fn();
Después dentro de MongoLibStub, donde declaramos a getAll, le asignamos mockGetAll.
{ getAll: mockGetAll, }
Ahora modificamos la respuesta del método getAll, con la función mockResolvedValue(fakeBooks)
// Retorna una promesa mockGetAll.mockResolvedValue(fakeBooks);
Y ahora podemos utilizar los métodos toHaveBeenCalled toHaveBeenCalledTimes toHaveBeenCalledWith para espiar y comprabor que el comportamiento interno de nuestro método sea el correcto.
expect(mockGetAll).toHaveBeenCalled(); expect(mockGetAll).toHaveBeenCalledTimes(1); expect(mockGetAll).toHaveBeenCalledWith('books', {});
Consideraciones
En esta clase estamos haciendo el test de lo que deberia retornar el metodo getBooks() de la la clase BooksService, pero si se quisiera hacer el test de la conexion a la base y comprobar que es lo que en realidad retorna la consulta, se deberia crear mas test para cada funcion/metodo en este caso en particular se deberia crear el test para el metodo getAll() de la clase MongoLib?
En este caso cuando utilizo el nombre spyGetAll siempre me da error, pero cuando uso el nombre mockGetAll todo sale correcto. Esto se debe a que jest tiene algun estandar para estas definiciones?
Exacto jest si o si dice que debemos llamarlo mock al inicio otra forma es organizar neustros mocks en la carpeta mocks que nos sugiere jest.
Spies son fundamentales para la observabilidad durante las pruebas.
¿Qué es un Spy?
Es un objeto que registra llamadas a funciones o métodos. A diferencia de un mock, no reemplaza el comportamiento original, sino que "espía" cómo se utiliza.
Funciones clave
Por que en un momento (la clase anterior) funciono el mockResolveValue y ahora tiene que ser mockResolvedValue?
Tengo una pregunta y tal vez un aporte al mismo tiempo. Vengo de hacer varios cursos de Testing con Nico en Angular y otros cursos de Testing con Node de otras plataformas y me surge una duda, Nico menciona que en las pruebas unitarias debemos centrarnos en el archivo que estamos trabajando, en este caso estamos un paso más allá, estamos involucrando archivos como el “mongo.lib.js” el cual debería tener su testing por aparte. ¿No se supone que no deberíamos tocar el archivo de “mongo.lib.js”, es decir, no debemos irnos más allá del servicio porque no son pruebas de integración, el proceso adecuado no sería crear un SPY del Servicio y controlar el getBooks y createBook desde el servicio mas no del mongo.lib, en otros cursos de testing con Node y Frameworks suele ser de la manera como lo estoy diciendo, nose si me estoy equivocando? Mi solución alternativa es con SpyOn en el Servicio mas no en el MongoLib, con SpyOn es mas corto y menos enredado.
const BooksService = require("./books.service"); const fakeBook = [ { _id: 1, name: "Iron Man", }, ]; const fakeBooks = [ { _id: 1, name: "Harry Potter", }, { _id: 2, name: "Señor de los Anillos", }, ]; describe("Test for BooksService", () => { let service; beforeEach(() => { service = new BooksService(); jest.clearAllMocks(); }); //Nico with mockImplementation //Owner with spyOn describe("Test for BooksService [Owner - spyOn]", () => { describe("test for getBooks with spyOn in BooksService", () => { test("should return a list book", async () => { //Arranger const spyGetAll = jest.spyOn(service, "getBooks"); spyGetAll.mockResolvedValue(fakeBooks); //Act const books = await service.getBooks({}); //Assert expect(books.length).toEqual(2); expect(spyGetAll).toHaveBeenCalled(); expect(spyGetAll).toHaveBeenCalledWith({}); }); test("should do match with name of first element", async () => { //Arranger const spyGetAll = jest.spyOn(service, "getBooks"); spyGetAll.mockResolvedValue(fakeBook); //Act const books = await service.getBooks({}); //Assert expect(books.length).toEqual(1); expect(books[0].name).toEqual("Iron Man"); }); }); }); });
Tengo una pregunta y tal vez un aporte al mismo tiempo. Vengo de hacer varios cursos de Testing con Nico en Angular y otros cursos de Testing con Node de otras plataformas y me surge una duda, Nico menciona que en las pruebas unitarias debemos centrarnos en el archivo que estamos trabajando, en este caso estamos un paso más allá, estamos involucrando archivos como el “mongo.lib.js” el cual debería tener su testing por aparte. ¿No se supone que no deberíamos tocar el archivo de “mongo.lib.js”, es decir, no debemos irnos más allá del servicio porque no son pruebas de integración, el proceso adecuado no sería crear un SPY del Servicio y controlar el getBooks y createBook desde el servicio mas no del mongo.lib, en otros cursos de testing con Node y Frameworks suele ser de la manera como lo estoy diciendo, nose si me estoy equivocando? Mi solución alternativa es con SpyOn en el Servicio mas no en el MongoLib, con SpyOn es mas corto y menos enredado.
const <u>BooksService</u> = require("./books.service"); const fakeBook = [ { _id: 1, name: "Iron Man", },];const fakeBooks = [ { _id: 1, name: "Harry Potter", }, { _id: 2, name: "Señor de los Anillos", },];const BooksService = require("./books.service"); const fakeBook = [ { _id: 1, name: "Iron Man", }, ]; const fakeBooks = [ { _id: 1, name: "Harry Potter", }, { _id: 2, name: "Señor de los Anillos", }, ];
Tengo una pregunta y tal vez un aporte al mismo tiempo. Vengo de hacer varios cursos de Testing con Nico en Angular y otros cursos de Testing con Node de otras plataformas y me surge una duda, Nico menciona que en las pruebas unitarias debemos centrarnos en el archivo que estamos trabajando, en este caso estamos un paso más allá, estamos involucrando archivos como el “mongo.lib.js” el cual debería tener su testing por aparte. ¿No se supone que no deberíamos tocar el archivo de “mongo.lib.js”, es decir, no debemos irnos más allá del servicio porque no son pruebas de integración, el proceso adecuado no sería crear un SPY del Servicio y controlar el getBooks y createBook desde el servicio mas no del mongo.lib, en otros cursos de testing con Node y Frameworks suele ser de la manera como lo estoy diciendo, nose si me estoy equivocando? Mi solución alternativa es con SpyOn en el Servicio mas no en el MongoLib, con SpyOn es mas corto y menos enredado.
const`` ``BooksService`` = require("./books.service");
const`` fakeBook = [ { _id: 1, name: "Iron Man", },];``const`` fakeBooks = [ { _id: 1, name: "Harry Potter", }, { _id: 2, name: "Señor de los Anillos", },];
describe("Test for BooksService", () ``=>`` { ``let`` service; beforeEach(() ``=>`` { service = new ``BooksService``(); jest.clearAllMocks(); });
//Nico with mockImplementation
//Owner with spyOn describe("Test for BooksService [Owner - spyOn]", () ``=>`` { describe("test for getBooks with spyOn in BooksService", () ``=>`` { test("should return a list book", async () ``=>`` { //Arranger ``const`` spyGetAll = jest.spyOn(service, "getBooks"); spyGetAll.mockResolvedValue(fakeBooks); //Act ``const`` books = await service.getBooks({}); //Assert expect(books.length).toEqual(2); expect(spyGetAll).toHaveBeenCalled(); expect(spyGetAll).toHaveBeenCalledWith({}); }); test("should do match with name of first element", async () ``=>`` { //Arranger ``const`` spyGetAll = jest.spyOn(service, "getBooks"); spyGetAll.mockResolvedValue(fakeBook); //Act ``const`` books = await service.getBooks({}); //Assert expect(books.length).toEqual(1); expect(books[0].name).toEqual("Iron Man"); }); }); });});
Tengo una pregunta y tal vez un aporte al mismo tiempo. Vengo de hacer varios cursos de Testing con Nico en Angular y otros cursos de Testing con Node de otras plataformas y me surge una duda, Nico menciona que en las pruebas unitarias debemos centrarnos en el archivo que estamos trabajando, en este caso estamos un paso más allá, estamos involucrando archivos como el “mongo.lib.js” el cual debería tener su testing por aparte. ¿No se supone que no deberíamos tocar el archivo de “mongo.lib.js”, es decir, no debemos irnos más allá del servicio porque no son pruebas de integración, el proceso adecuado no sería crear un SPY del Servicio y controlar el getBooks y createBook desde el servicio mas no del mongo.lib, en otros cursos de testing con Node y Frameworks suele ser de la manera como lo estoy diciendo, nose si me estoy equivocando? Mi solución alternativa es con SpyOn en el Servicio mas no en el MongoLib, con SpyOn es mas corto y menos enredado.const <u>BooksService</u> = require("./books.service"); const fakeBook = [ { _id: 1, name: "Iron Man", },];const fakeBooks = [ { _id: 1, name: "Harry Potter", }, { _id: 2, name: "Señor de los Anillos", },];```js const BooksService = require("./books.service");
const fakeBook = [ { _id: 1, name: "Iron Man", }, ]; const fakeBooks = [ { _id: 1, name: "Harry Potter", }, { _id: 2, name: "Señor de los Anillos", }, ];
describe("Test for BooksService", () => { let service; beforeEach(() => { service = new BooksService(); jest.clearAllMocks(); });
//Nico with mockImplementation
//Owner with spyOn describe("Test for BooksService [Owner - spyOn]", () => { describe("test for getBooks with spyOn in BooksService", () => { test("should return a list book", async () => { //Arranger const spyGetAll = jest.spyOn(service, "getBooks"); spyGetAll.mockResolvedValue(fakeBooks); //Act const books = await service.getBooks({}); //Assert expect(books.length).toEqual(2); expect(spyGetAll).toHaveBeenCalled(); expect(spyGetAll).toHaveBeenCalledWith({}); }); test("should do match with name of first element", async () => { //Arranger const spyGetAll = jest.spyOn(service, "getBooks"); spyGetAll.mockResolvedValue(fakeBook); //Act const books = await service.getBooks({}); //Assert expect(books.length).toEqual(1); expect(books[0].name).toEqual("Iron Man"); }); }); }); });
Tuve que aclarar esta duda interna que tenía
Mocks:
Un "mock" es un objeto simulado que imita el comportamiento de un componente real.
Spies:
Un "spy" es similar a un "mock" en el sentido de que también registra y verifica el comportamiento de un objeto durante una prueba. Sin embargo, a diferencia de un mock que imita completamente el objeto real, un "spy" es una versión parcialmente real del objeto que está siendo probado. Los "spies" se utilizan para espiar y registrar el comportamiento de métodos o funciones específicas de un objeto, mientras que el resto del objeto se comporta como lo haría normalmente.