Las pruebas unitarias son una parte esencial del desarrollo de software, ya que permiten verificar que las unidades individuales de código (como funciones, métodos o clases) funcionan correctamente. En Angular, las pruebas unitarias se realizan utilizando herramientas como Jasmine y Karma.

¿Qué son las Pruebas Unitarias?

Las pruebas unitarias son pruebas automatizadas que verifican el comportamiento de una pequeña parte del código, generalmente una función o un método. El objetivo es asegurarse de que cada unidad de código funcione correctamente de manera aislada.

Beneficios de las Pruebas Unitarias

  • Detección temprana de errores: Permiten identificar errores en el código de manera temprana.
  • Facilitan el mantenimiento: Ayudan a mantener el código limpio y libre de errores a lo largo del tiempo.
  • Documentación: Actúan como documentación viva del comportamiento esperado del código.
  • Refactorización segura: Permiten realizar cambios en el código con la confianza de que no se romperá la funcionalidad existente.

Configuración del Entorno de Pruebas

Angular CLI viene preconfigurado con Jasmine y Karma para realizar pruebas unitarias. No obstante, es importante entender cómo están configuradas estas herramientas.

Jasmine

Jasmine es un framework de pruebas para JavaScript que permite escribir pruebas de manera sencilla y legible.

Karma

Karma es un ejecutor de pruebas que permite ejecutar las pruebas en diferentes navegadores.

Configuración Inicial

Cuando creas un nuevo proyecto Angular con Angular CLI, se genera automáticamente una configuración básica para Jasmine y Karma. Puedes encontrar los archivos de configuración en la raíz del proyecto:

  • karma.conf.js: Configuración de Karma.
  • src/test.ts: Archivo de entrada para las pruebas.

Escribiendo Pruebas Unitarias en Angular

Estructura de una Prueba Unitaria

Una prueba unitaria en Jasmine se estructura de la siguiente manera:

  1. Describe: Define un conjunto de pruebas relacionadas.
  2. It: Define una prueba individual.
  3. Expect: Define una expectativa sobre el resultado del código.
describe('MiFunción', () => {
  it('debería retornar verdadero cuando el valor es positivo', () => {
    const resultado = miFunción(1);
    expect(resultado).toBe(true);
  });
});

Pruebas de Componentes

Para probar componentes en Angular, se utiliza el TestBed, que es una utilidad proporcionada por Angular para configurar y crear un entorno de pruebas.

Ejemplo de Prueba de Componente

Supongamos que tenemos un componente AppComponent que queremos probar.

import { TestBed, ComponentFixture } from '@angular/core/testing';
import { AppComponent } from './app.component';

describe('AppComponent', () => {
  let component: AppComponent;
  let fixture: ComponentFixture<AppComponent>;

  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [AppComponent]
    }).compileComponents();

    fixture = TestBed.createComponent(AppComponent);
    component = fixture.componentInstance;
  });

  it('debería crear el componente', () => {
    expect(component).toBeTruthy();
  });

  it('debería tener como título "mi-app"', () => {
    expect(component.title).toBe('mi-app');
  });

  it('debería renderizar el título en un h1', () => {
    fixture.detectChanges();
    const compiled = fixture.nativeElement;
    expect(compiled.querySelector('h1').textContent).toContain('Bienvenido a mi-app!');
  });
});

Pruebas de Servicios

Para probar servicios, se utiliza el TestBed para configurar el entorno de pruebas y proporcionar las dependencias necesarias.

Ejemplo de Prueba de Servicio

Supongamos que tenemos un servicio DataService que queremos probar.

import { TestBed } from '@angular/core/testing';
import { DataService } from './data.service';

describe('DataService', () => {
  let service: DataService;

  beforeEach(() => {
    TestBed.configureTestingModule({});
    service = TestBed.inject(DataService);
  });

  it('debería ser creado', () => {
    expect(service).toBeTruthy();
  });

  it('debería retornar datos', () => {
    const datos = service.getData();
    expect(datos).toEqual(['dato1', 'dato2', 'dato3']);
  });
});

Ejercicios Prácticos

Ejercicio 1: Prueba de una Función

Crea una función suma que tome dos números y retorne su suma. Escribe una prueba unitaria para verificar que la función funciona correctamente.

Solución

// función suma
export function suma(a: number, b: number): number {
  return a + b;
}

// prueba unitaria
describe('suma', () => {
  it('debería retornar la suma de dos números', () => {
    expect(suma(1, 2)).toBe(3);
    expect(suma(-1, 1)).toBe(0);
  });
});

Ejercicio 2: Prueba de un Componente

Crea un componente SaludoComponent que tenga una propiedad nombre y un método saludar que retorne un saludo. Escribe pruebas unitarias para verificar que el componente funciona correctamente.

Solución

// saludo.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-saludo',
  template: '<h1>{{ saludar() }}</h1>'
})
export class SaludoComponent {
  nombre: string = 'Angular';

  saludar(): string {
    return `Hola, ${this.nombre}!`;
  }
}

// saludo.component.spec.ts
import { TestBed, ComponentFixture } from '@angular/core/testing';
import { SaludoComponent } from './saludo.component';

describe('SaludoComponent', () => {
  let component: SaludoComponent;
  let fixture: ComponentFixture<SaludoComponent>;

  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [SaludoComponent]
    }).compileComponents();

    fixture = TestBed.createComponent(SaludoComponent);
    component = fixture.componentInstance;
  });

  it('debería crear el componente', () => {
    expect(component).toBeTruthy();
  });

  it('debería tener como nombre "Angular"', () => {
    expect(component.nombre).toBe('Angular');
  });

  it('debería retornar un saludo', () => {
    expect(component.saludar()).toBe('Hola, Angular!');
  });

  it('debería renderizar el saludo en un h1', () => {
    fixture.detectChanges();
    const compiled = fixture.nativeElement;
    expect(compiled.querySelector('h1').textContent).toContain('Hola, Angular!');
  });
});

Conclusión

Las pruebas unitarias son una herramienta poderosa para asegurar la calidad y la estabilidad del código en aplicaciones Angular. Al aprender a escribir y ejecutar pruebas unitarias, puedes detectar errores de manera temprana, facilitar el mantenimiento del código y realizar refactorizaciones con confianza. En el próximo tema, exploraremos las pruebas de componentes en mayor detalle, profundizando en cómo probar la interacción y el comportamiento de los componentes en 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