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.

  1. 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.

  1. 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.

  1. 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.

  1. 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

Mòdul 2: Conceptes bàsics de TypeScript

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

Mòdul 9: Gestió d'estat

Mòdul 10: Proves en Angular

Mòdul 11: Temes avançats

Mòdul 12: Desplegament i millors pràctiques

© Copyright 2024. Tots els drets reservats