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
HttpClientTestingModuleper 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
