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:
- Describe: Define un conjunto de pruebas relacionadas.
- It: Define una prueba individual.
- 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
- ¿Qué es Angular?
- Configuración del Entorno de Desarrollo
- Arquitectura de Angular
- Primera Aplicación Angular
Módulo 2: Componentes de Angular
- Entendiendo los Componentes
- Creación de Componentes
- Plantillas de Componentes
- Estilos de Componentes
- Interacción entre Componentes
Módulo 3: Enlace de Datos y Directivas
- Interpolación y Enlace de Propiedades
- Enlace de Eventos
- Enlace de Datos Bidireccional
- Directivas Incorporadas
- Directivas Personalizadas
Módulo 4: Servicios e Inyección de Dependencias
- Introducción a los Servicios
- Creación y Uso de Servicios
- Inyección de Dependencias
- Inyectores Jerárquicos
Módulo 5: Enrutamiento y Navegación
Módulo 6: Formularios en Angular
- Formularios Basados en Plantillas
- Formularios Reactivos
- Validación de Formularios
- Formularios Dinámicos
Módulo 7: Cliente HTTP y Observables
- Introducción al Cliente HTTP
- Realizando Solicitudes HTTP
- Manejo de Respuestas HTTP
- Uso de Observables
- Manejo de Errores
Módulo 8: Gestión de Estado
- Introducción a la Gestión de Estado
- Uso de Servicios para la Gestión de Estado
- NgRx Store
- NgRx Effects
- NgRx Entity
Módulo 9: Pruebas en Angular
- Pruebas Unitarias
- Pruebas de Componentes
- Pruebas de Servicios
- Pruebas de Extremo a Extremo
- Simulación de Dependencias
Módulo 10: Conceptos Avanzados de Angular
- Angular Universal
- Optimización del Rendimiento
- Internacionalización (i18n)
- Pipes Personalizados
- Animaciones en Angular