En aquest tema, aprendrem com realitzar proves de serveis en Angular. Els serveis són una part fonamental de qualsevol aplicació Angular, ja que encapsulen la lògica de negoci i proporcionen funcionalitats reutilitzables. Les proves de serveis asseguren que aquesta lògica funcioni correctament i que els serveis es comportin com s'espera.
Objectius
- Comprendre la importància de les proves de serveis.
- Aprendre a configurar i escriure proves unitàries per a serveis Angular.
- Utilitzar
HttpClientTestingModule
per provar serveis que fan sol·licituds HTTP. - Veure exemples pràctics de proves de serveis.
- Importància de les proves de serveis
Les proves de serveis són crucials per diverses raons:
- Fiabilitat: Asseguren que la lògica de negoci funcioni correctament.
- Mantenibilitat: Faciliten la detecció de regressions quan es fan canvis en el codi.
- Documentació: Les proves poden servir com a documentació viva del comportament esperat dels serveis.
- Configuració de les proves de serveis
2.1. Instal·lació de dependències
Angular ve amb el framework de proves Jasmine i l'executor de proves Karma preconfigurats. No cal instal·lar res addicional per començar a escriure proves unitàries.
2.2. Configuració bàsica
Per provar un servei, primer hem de configurar un mòdul de proves. Utilitzarem TestBed
per configurar l'entorn de proves.
import { TestBed } from '@angular/core/testing'; import { MyService } from './my-service.service'; describe('MyService', () => { let service: MyService; beforeEach(() => { TestBed.configureTestingModule({ providers: [MyService] }); service = TestBed.inject(MyService); }); it('should be created', () => { expect(service).toBeTruthy(); }); });
Explicació del codi
TestBed.configureTestingModule
: Configura un mòdul de proves amb els proveïdors necessaris.TestBed.inject(MyService)
: Obté una instància del servei que volem provar.it('should be created')
: Una prova bàsica per assegurar que el servei es crea correctament.
- Proves de serveis amb dependències
Si el servei que estem provant té dependències, hem de proporcionar aquestes dependències en el mòdul de proves.
import { TestBed } from '@angular/core/testing'; import { MyService } from './my-service.service'; import { DependentService } from './dependent-service.service'; describe('MyService', () => { let service: MyService; let dependentServiceSpy: jasmine.SpyObj<DependentService>; beforeEach(() => { const spy = jasmine.createSpyObj('DependentService', ['someMethod']); TestBed.configureTestingModule({ providers: [ MyService, { provide: DependentService, useValue: spy } ] }); service = TestBed.inject(MyService); dependentServiceSpy = TestBed.inject(DependentService) as jasmine.SpyObj<DependentService>; }); it('should call someMethod from DependentService', () => { service.callDependentServiceMethod(); expect(dependentServiceSpy.someMethod).toHaveBeenCalled(); }); });
Explicació del codi
jasmine.createSpyObj
: Crea un objecte espia per a la dependència.{ provide: DependentService, useValue: spy }
: Proporciona l'objecte espia com a dependència.expect(dependentServiceSpy.someMethod).toHaveBeenCalled()
: Verifica que el mètode de la dependència s'ha cridat.
- Proves de serveis amb sol·licituds HTTP
Quan un servei fa sol·licituds HTTP, utilitzem HttpClientTestingModule
per interceptar i controlar aquestes sol·licituds en les proves.
4.1. Configuració
import { TestBed } from '@angular/core/testing'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { MyService } from './my-service.service'; describe('MyService', () => { let service: MyService; let httpMock: HttpTestingController; beforeEach(() => { TestBed.configureTestingModule({ imports: [HttpClientTestingModule], providers: [MyService] }); service = TestBed.inject(MyService); httpMock = TestBed.inject(HttpTestingController); }); afterEach(() => { httpMock.verify(); }); it('should fetch data from API', () => { const mockData = { key: 'value' }; service.getData().subscribe(data => { expect(data).toEqual(mockData); }); const req = httpMock.expectOne('api/data'); expect(req.request.method).toBe('GET'); req.flush(mockData); }); });
Explicació del codi
HttpClientTestingModule
: Mòdul que proporciona eines per provar sol·licituds HTTP.HttpTestingController
: Controlador que permet interceptar i verificar sol·licituds HTTP.httpMock.expectOne('api/data')
: Verifica que s'ha fet una sol·licitud a l'URL especificat.req.flush(mockData)
: Simula una resposta HTTP amb les dades proporcionades.
Exercicis pràctics
Exercici 1: Prova bàsica de servei
Crea un servei senzill que retorni una cadena de text i escriu una prova per verificar que el servei retorna la cadena correcta.
Solució
// my-simple-service.service.ts import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class MySimpleService { getMessage(): string { return 'Hello, Angular!'; } } // my-simple-service.service.spec.ts import { TestBed } from '@angular/core/testing'; import { MySimpleService } from './my-simple-service.service'; describe('MySimpleService', () => { let service: MySimpleService; beforeEach(() => { TestBed.configureTestingModule({ providers: [MySimpleService] }); service = TestBed.inject(MySimpleService); }); it('should return the correct message', () => { expect(service.getMessage()).toBe('Hello, Angular!'); }); });
Exercici 2: Prova de servei amb dependència
Crea un servei que depengui d'un altre servei i escriu una prova per verificar que la dependència es crida correctament.
Solució
// dependent-service.service.ts import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class DependentService { someMethod(): void { console.log('Method called'); } } // my-dependent-service.service.ts import { Injectable } from '@angular/core'; import { DependentService } from './dependent-service.service'; @Injectable({ providedIn: 'root' }) export class MyDependentService { constructor(private dependentService: DependentService) {} callDependentServiceMethod(): void { this.dependentService.someMethod(); } } // my-dependent-service.service.spec.ts import { TestBed } from '@angular/core/testing'; import { MyDependentService } from './my-dependent-service.service'; import { DependentService } from './dependent-service.service'; describe('MyDependentService', () => { let service: MyDependentService; let dependentServiceSpy: jasmine.SpyObj<DependentService>; beforeEach(() => { const spy = jasmine.createSpyObj('DependentService', ['someMethod']); TestBed.configureTestingModule({ providers: [ MyDependentService, { provide: DependentService, useValue: spy } ] }); service = TestBed.inject(MyDependentService); dependentServiceSpy = TestBed.inject(DependentService) as jasmine.SpyObj<DependentService>; }); it('should call someMethod from DependentService', () => { service.callDependentServiceMethod(); expect(dependentServiceSpy.someMethod).toHaveBeenCalled(); }); });
Conclusió
En aquesta secció, hem après com configurar i escriure proves unitàries per a serveis Angular. Hem vist com provar serveis amb i sense dependències, així com serveis que fan sol·licituds HTTP. Les proves de serveis són una part essencial per assegurar la qualitat i la fiabilitat de les aplicacions Angular. Amb aquestes habilitats, estàs preparat per escriure proves robustes per als teus serveis i millorar la qualitat del teu codi.
Curs d'Angular 2+
Mòdul 1: Introducció a Angular
- Què és Angular?
- Configuració de l'entorn de desenvolupament
- La teva primera aplicació Angular
- Arquitectura d'Angular
Mòdul 2: Conceptes bàsics de TypeScript
- Introducció a TypeScript
- Variables i tipus de dades en TypeScript
- Funcions i funcions fletxa
- Classes i interfícies
Mòdul 3: Components i plantilles
Mòdul 4: Directives i pipes
Mòdul 5: Serveis i injecció de dependències
Mòdul 6: Enrutament i navegació
Mòdul 7: Formularis en Angular
Mòdul 8: Client HTTP i observables
- Introducció al client HTTP
- Realització de sol·licituds HTTP
- Gestió de respostes HTTP
- Ús d'observables