No tienes acceso a esta clase

隆Contin煤a aprendiendo! 脷nete y comienza a potenciar tu carrera

Aprende todo un fin de semana sin pagar una suscripci贸n 馃敟

Aprende todo un fin de semana sin pagar una suscripci贸n 馃敟

Reg铆strate

Comienza en:

2D
4H
20M
11S

Servicios con dependencias

8/25
Recursos

Aportes 5

Preguntas 1

Ordenar por:

驴Quieres ver m谩s aportes, preguntas y respuestas de la comunidad?

o inicia sesi贸n.

Angular tiene un concepto importante conocido como inyecci贸n de dependencias. Es decir que podemos inyectar servicios, componentes, directivas o pipes a otros componentes, directivas, pipes, etc.

En estos casos cuando un servicio depende de otro o un componente depende de otro se debe realizar pruebas de la siguiente manera.

primero crearemos un servicio extra

ng g s services/master

y vamos a ingrersar el siguiente c贸digo

master.service.ts

import { Injectable } from '@angular/core';

import 聽{ ValueService } from './value.service';

@Injectable({
聽 providedIn: 'root'
})

export class MasterService {
聽 constructor(
聽 聽 private valueService: ValueService
聽 ) { }

聽 getValue() {
聽 聽 return this.valueService.getValue();
聽 }
}

Como se puede observar masterService tiene una inyecci贸n de dependencia de valueService.

Para poder realizar las pruebas en valueService ingresar el siguiente c贸digo en el master.service.spec.ts

master.service.spec.ts

import { MasterService } from './master.service';
import { ValueService } from './value.service';

describe('MasterService', () => {
聽 it('should be return "my value" from the real service', () => {
聽 聽 const valueService = new ValueService();
聽 聽 const masterService = new MasterService(valueService);
聽 聽 expect(masterService.getValue()).toBe('my value');
聽 });
});

como masterService recibe como parametro en su contructor un servicio de valueService, para poder realizar las pruebas desde masterService es necesario crear ambas instancias y enviar en masterService a valueService como parametro.

Importante

En las pruebas unitarias, todo lo que venga como dependencias lo vamos a ejecutar de forma fake o mock.
Quiere decir que solo se va a verificar la funcionalidad exacta de esa prueba por ejemplo

Si getValue en valueService es probada, su test sera ver si devuelve el valor asignado en la variable privada value.

Mientras que si la funci贸n getValue es provada desde masterService, su test verificara si se esta llamando correctamente la funci贸n getValue desde ValueService.

Por lo que para probar se debera hacer mocks de todo lo que venga como dependencias. Por que lo 煤nico que se debe probar es su ejecuci贸n, no si funciona como tal

Mocks o servicios tipo fake

para observar lo que se hace en un mock vamos a crear un archivo dentro de services llamado 鈥榲alue-fake.service.ts鈥 y a帽adimos las funcionalidades de value.service

value-fake.service.ts

export class FakeValueService {

聽 constructor() { }

聽 getValue() {
聽 聽 return 'fake value';
聽 }

聽 setValue (value: string) { }

getPromiseValue() {
聽 聽 return Promise.resolve('fake promise value');
聽 }

}

Ahora lo importamos a nuestro master value y configuramos mediante un as unknow as ValueService para verificar que se ejecuta la prueba sin necesidad de observar si las funciones de value service se producen correctamente.

master.service.spec.ts

import { FakeValueService } from './value-fake.service';

it('should be return "other value" from the fake service', () => {
聽 聽 const fakeValueService = new FakeValueService();
聽 聽 const masterService = new MasterService(fakeValueService as unknown as ValueService);
聽 聽 expect(masterService.getValue()).toBe('fake value');
聽 });

Esta es la forma menos eficiente de hacer pruebas sobretodo de mantenimiento.

Otra forma de hacerlo es con un objeto, por que los objetos en JS funcionan como clases o casi como clases por lo que puedo hacer que se pase directamente con un objeto en master.service.spec.ts.

Por lo que, cuando master service lo ejecute probara un fake que se esta enviando en forma de objeto

master.service.spec.ts

it('should be return "other value" from the fake object', () => {
聽 聽 const fake = {getValue: () => 'fake from obj'};
聽 聽 const masterService = new MasterService(fake as ValueService);
聽 聽 expect(masterService.getValue()).toBe('fake from obj');
聽 });

Esto es especialemente util al momento de probar funcionalidades que por ejemplo se conectan a una API como google maps.
Si al momento de hacer pruebas llamamos al API KEY de google maps se puede consumir tantas veces el servicio de manera consecutiva que

  1. consumiria mucho saldo por uso de la API KEY
  2. podr铆a verse como un ataque de DNS y cancelar tus servicios.

Para evitar todo esto se enviar un fake y con eso evitamos el consumo inutil de servicios.

Existen m茅todos para no ejecutar un servicio de dependencia real sino uno fake, con el prop贸sito de emular las respuestas, permiti茅ndonos centrarnos en el servicio a testear y no en las dependencias.

Fake Services: Hacer mocks/clones de los servicios dependencia (m茅todo poco mantenible)

Esto es un cascar贸n del servicio, retornando m茅todos con valores predefinidos, fakes.

it('sould return "other value" from the fake service', () => {
    const fakeValueService = new FakeValueService();
    const masterService = new MasterService(fakeValueService as unknown as ValueService);
    expect(masterService.getValue()).toBe('fake value');
  });

Usar objetos como clases:

Nos permite hacer una funci贸n dentro de un objeto en la misma prueba, emulando el m茅todo a testear.

it('sould return "fake from obj" from the fake object', () => {
    const fake = { getValue:()=>'fake from obj' }
    const masterService = new MasterService(fake as ValueService);
    expect(masterService.getValue()).toBe('fake from obj');
  });

Estas formas son manuales, hay maneras automatizadas de hacerlo con Spies

No he llegado a la mitad, y ya me exploto la cabeza.

Hubiera sido bueno que getValue() de master, hubiera tenido un nombre diferente a getValue de Value.service.

As铆, no ser铆a un trabalenguas

Servicios

馃挕 Lo servicios en Angular funcionan gracias al patr贸n de Inyecci贸n de dependencias, el cual nos permite inyectar nuestro servicios en diferentes lugares c贸mo componentes, directivas, etc.

C贸mo desarrolladores, tambi茅n nos encontraremos con el escenario d贸nde tengamos que probar componentes que depende de un servicio e incluso, servicios depende de otros servicios. Es ah铆 donde la inyecci贸n de dependencias puede ser una herramienta o un problema m谩s (sino la podemos usar).

Algo a tener en cuenta, es que nuestra pruebas unitarias deben encargarse solamente de evaluar la responsabilidad que le corresponde a la funci贸n o clase que estamos evaluando.

馃挕 Es decir, a un conjunto de pruebas unitarias no le debe importar s铆 una dependencia funciona bien o no, ya que dicha dependencia deber铆a tener su conjunto de pruebas unitarias que se encarguen de verificar su correcto funcionamiento.

Una forma de hacer pruebas unitarias de un servicio que depende de otros servicios es utilizar la t茅cnica de inyecci贸n de dependencias. Esto implica proporcionar a la clase o funci贸n que se est谩 probando una instancia de cada uno de los servicios que depende, en lugar de crearlos directamente en el c贸digo.

De esta manera, puedes proporcionar versiones 鈥渟imuladas鈥 o 鈥渕ock鈥 de los servicios dependientes durante las pruebas, lo que te permite controlar el comportamiento de los servicios dependientes y asegurar que tu c贸digo se est谩 ejecutando correctamente.

Puedes crear mock services (u objects) para cada uno de los servicios que depende tu servicio y configurarlos para que devuelvan valores predefinidos cuando se llamen. Esto te permite probar tu servicio de manera aislada sin depender de los servicios reales, lo cual es realmente 煤til cuando quieres probar servicios que se conecta a una API (por citar un ejemplo), debido a que de esta manera, te evitas el consumo de recursos externos.

鈿狅笍 Es fundamental asegurarte de que tus pruebas sean lo suficientemente exhaustivas para cubrir todos los casos de uso posibles y garantizar la calidad de tu c贸digo.