En este tema, aprenderemos sobre la simulación de dependencias en Angular, una técnica crucial para realizar pruebas unitarias efectivas. La simulación de dependencias nos permite aislar el código que estamos probando, asegurándonos de que las pruebas sean precisas y confiables.

¿Qué es la Simulación de Dependencias?

La simulación de dependencias (mocking) es el proceso de reemplazar componentes o servicios reales con versiones simuladas (mocks) durante las pruebas. Esto es útil para:

  • Aislar el código bajo prueba: Asegurarse de que las pruebas se centren en la funcionalidad específica sin interferencias externas.
  • Controlar el comportamiento de las dependencias: Simular diferentes escenarios y respuestas de las dependencias.
  • Mejorar la velocidad de las pruebas: Evitar dependencias costosas en términos de tiempo, como llamadas a bases de datos o servicios externos.

Beneficios de la Simulación de Dependencias

  • Aislamiento: Permite probar componentes de manera aislada.
  • Control: Facilita la simulación de diferentes condiciones y respuestas.
  • Fiabilidad: Asegura que las pruebas no dependan de factores externos.
  • Rapidez: Las pruebas se ejecutan más rápido al evitar dependencias externas.

Ejemplo Práctico: Simulación de un Servicio

Vamos a ver un ejemplo práctico de cómo simular un servicio en Angular utilizando Jasmine y TestBed.

Paso 1: Crear el Servicio

Primero, creamos un servicio simple que queremos simular.

// src/app/services/data.service.ts
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class DataService {
  getData(): string {
    return 'real data';
  }
}

Paso 2: Crear el Componente que Usa el Servicio

Creamos un componente que utiliza el servicio DataService.

// src/app/components/data.component.ts
import { Component, OnInit } from '@angular/core';
import { DataService } from '../services/data.service';

@Component({
  selector: 'app-data',
  template: '<p>{{ data }}</p>'
})
export class DataComponent implements OnInit {
  data: string;

  constructor(private dataService: DataService) {}

  ngOnInit(): void {
    this.data = this.dataService.getData();
  }
}

Paso 3: Configurar el TestBed y Simular el Servicio

Ahora configuramos el TestBed para simular el DataService.

// src/app/components/data.component.spec.ts
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { DataComponent } from './data.component';
import { DataService } from '../services/data.service';

class MockDataService {
  getData(): string {
    return 'mock data';
  }
}

describe('DataComponent', () => {
  let component: DataComponent;
  let fixture: ComponentFixture<DataComponent>;
  let dataService: DataService;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      declarations: [ DataComponent ],
      providers: [
        { provide: DataService, useClass: MockDataService }
      ]
    })
    .compileComponents();
  });

  beforeEach(() => {
    fixture = TestBed.createComponent(DataComponent);
    component = fixture.componentInstance;
    dataService = TestBed.inject(DataService);
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });

  it('should display mock data', () => {
    expect(component.data).toBe('mock data');
  });
});

Explicación del Código

  1. MockDataService: Creamos una clase MockDataService que simula el comportamiento del DataService real.
  2. TestBed Configuration: Configuramos el TestBed para usar MockDataService en lugar del DataService real.
  3. Pruebas: Verificamos que el componente se crea correctamente y que muestra los datos simulados.

Ejercicio Práctico

Ejercicio

  1. Crea un servicio UserService que tenga un método getUser() que devuelva un objeto de usuario.
  2. Crea un componente UserComponent que use UserService para obtener y mostrar el nombre del usuario.
  3. Escribe pruebas unitarias para UserComponent simulando UserService.

Solución

Paso 1: Crear el Servicio

// src/app/services/user.service.ts
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class UserService {
  getUser() {
    return { name: 'John Doe' };
  }
}

Paso 2: Crear el Componente

// src/app/components/user.component.ts
import { Component, OnInit } from '@angular/core';
import { UserService } from '../services/user.service';

@Component({
  selector: 'app-user',
  template: '<p>{{ user.name }}</p>'
})
export class UserComponent implements OnInit {
  user: any;

  constructor(private userService: UserService) {}

  ngOnInit(): void {
    this.user = this.userService.getUser();
  }
}

Paso 3: Configurar el TestBed y Simular el Servicio

// src/app/components/user.component.spec.ts
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { UserComponent } from './user.component';
import { UserService } from '../services/user.service';

class MockUserService {
  getUser() {
    return { name: 'Mock User' };
  }
}

describe('UserComponent', () => {
  let component: UserComponent;
  let fixture: ComponentFixture<UserComponent>;
  let userService: UserService;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      declarations: [ UserComponent ],
      providers: [
        { provide: UserService, useClass: MockUserService }
      ]
    })
    .compileComponents();
  });

  beforeEach(() => {
    fixture = TestBed.createComponent(UserComponent);
    component = fixture.componentInstance;
    userService = TestBed.inject(UserService);
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });

  it('should display mock user name', () => {
    expect(component.user.name).toBe('Mock User');
  });
});

Conclusión

La simulación de dependencias es una técnica poderosa para realizar pruebas unitarias efectivas en Angular. Permite aislar el código bajo prueba, controlar el comportamiento de las dependencias y mejorar la velocidad y fiabilidad de las pruebas. Con la práctica, podrás aplicar esta técnica para asegurar la calidad y robustez de tus aplicaciones Angular.

Curso de Angular

Módulo 1: Introducción a Angular

Módulo 2: Componentes de Angular

Módulo 3: Enlace de Datos y Directivas

Módulo 4: Servicios e Inyección de Dependencias

Módulo 5: Enrutamiento y Navegación

Módulo 6: Formularios en Angular

Módulo 7: Cliente HTTP y Observables

Módulo 8: Gestión de Estado

Módulo 9: Pruebas en Angular

Módulo 10: Conceptos Avanzados de Angular

Módulo 11: Despliegue y Mejores Prácticas

© Copyright 2024. Todos los derechos reservados