¡Bienvenido a este tutorial práctico de pruebas en AngularJS para principiantes!
Las pruebas son cruciales para construir aplicaciones AngularJS robustas, pero muchos desarrolladores las encuentran desafiantes. Este tutorial pretende hacer que probar código Angular sea sencillo mediante ejemplos fáciles de seguir.
Siguiendo los principios fundamentales de pruebas sobre aislamiento y simulación (mocking), obtendrás experiencia práctica creando tests mantenibles que detecten problemas rápidamente. Al final, tendrás las habilidades esenciales para construir aplicaciones AngularJS de nivel productivo que cumplan con los requisitos de funcionalidad, compatibilidad, confiabilidad y rendimiento.
Con un enfoque en la simplicidad y la aplicabilidad en el mundo real, este Tutorial de Pruebas en AngularJS te dará la confianza necesaria para crear aplicaciones AngularJS libres de errores.
¡Así que comencemos!
Herramientas Comunes de Pruebas en AngularJS
-
Cypress – Framework de pruebas de extremo a extremo (E2E) que se ejecuta directamente en navegadores modernos.
-
Karma – Ejecutor de pruebas (test runner) para pruebas unitarias de código AngularJS.
-
Protractor – Framework de pruebas de extremo a extremo para aplicaciones AngularJS.
Aplicaciones AngularJS – Componentes Clave
Al construir aplicaciones AngularJS, los desarrolladores trabajan con varios componentes clave que forman la estructura y funcionalidad de la app. Estos componentes trabajan juntos para crear la lógica, las vistas y los servicios subyacentes que impulsan la experiencia del usuario.
1. Controladores (Controllers):
Estas son funciones JavaScript que proporcionan la lógica de negocio detrás de las vistas. En el patrón de diseño MVC, los controladores actúan como el «control», manejando la entrada del usuario, manipulando datos y decidiendo qué contenido renderizar. En la práctica, los desarrolladores crean controladores para conectar los ámbitos (scopes) de AngularJS a las vistas.
2. Vistas (Views):
Definidas usando HTML, las vistas renderizan datos desde los controladores y modelos. Una característica clave es su uso del enlace de datos (data binding) para actualizarse automáticamente cuando cambian los datos del modelo, lo que elimina la necesidad de actualizaciones manuales.
3. Modelos (Models):
Pueden ser objetos JavaScript simples o derivarse de un framework de persistencia como Firebase. Su propósito es representar los conceptos de datos de la aplicación en una estructura adecuada para las vistas.
4. Servicios (Services):
Los servicios de AngularJS realizan tareas como llamadas a API sin saturar el código del controlador. Además, los servicios pueden compartirse en toda la aplicación, lo que aumenta la flexibilidad y la reutilización.
5. Módulos (Modules):
Los desarrolladores definen módulos usando ng-app para declarar las dependencias de la aplicación y el componente de entrada. Este enfoque mejora la organización y mantiene una separación de responsabilidades (separation of concerns).
Al aprovechar estos componentes clave, los desarrolladores pueden construir aplicaciones web AngularJS robustas con una clara separación de responsabilidades entre las diferentes capas. En última instancia, la flexibilidad de los componentes de AngularJS permite crear experiencias de usuario complejas e impulsadas por datos.
Pruebas Unitarias en AngularJS
Las pruebas unitarias en AngularJS son esenciales para construir aplicaciones de alta calidad porque validan que componentes individuales como controladores, directivas y servicios funcionen como se espera.
Los beneficios clave incluyen: detectar errores temprano, permitir la refactorización segura del código y simplificar la integración de código de diferentes desarrolladores. Por lo tanto, antes de que una aplicación AngularJS pueda considerarse lista para producción, debe someterse a pruebas unitarias exhaustivas para detectar problemas en la etapa más temprana posible.
Como resultado, unas pruebas unitarias robustas conducen a aplicaciones que son más confiables, mejor optimizadas y más alineadas con los requisitos del negocio. También permiten diagnosticar y corregir errores rápidamente, dando a los usuarios una mayor confianza en las capacidades de la aplicación.
Fundamentos de las Pruebas Unitarias en AngularJS
Al escribir pruebas unitarias para tu código AngularJS, seguir estos fundamentos garantizará que tu conjunto de pruebas sea robusto, mantenible y sostenible a medida que tu aplicación evoluciona:
-
Aísla las Dependencias: Cada prueba unitaria debe probar un componente específico de forma aislada, sin depender de otros módulos o dependencias externas. Usa mocks, espías (spies) y stubs para simular dependencias.
-
Organizar, Actuar, Afirmar (AAA): Estructura tu prueba en tres secciones claramente definidas: organiza los datos/entradas de la prueba, ejecuta la lógica a probar (actuar) y afirma que se produjo la salida esperada.
-
Una Afirmación por Prueba: Cada caso de prueba debe validar un comportamiento o salida para facilitar la identificación de lo que falló. Evita afirmaciones que verifiquen múltiples salidas.
-
Haz las Pruebas Independientes: Escribe casos de prueba que configuren sus propios datos de prueba para que puedan ejecutarse de forma independiente y no dependan del orden de ejecución. Esto es especialmente útil al ejecutar pruebas en paralelo.
-
Mantén las Pruebas Breves y Legibles: Divide los casos de prueba extensos en funciones auxiliares más pequeñas que prueben un solo comportamiento o una subunidad de un componente.
Seguir estas pautas fundamentales garantizará que tu conjunto de pruebas unitarias de AngularJS permanezca robusto y fácil de extender con el tiempo a medida que crece la complejidad de la aplicación.
Configurar tu Entorno
Para comenzar con las pruebas unitarias, solo sigue estos pasos:
1. Instalar los Requisitos Previos
-
Instala Node.js en tu computadora, ya que es el framework sobre el que construiremos.
-
Abre tu editor de código favorito (por ejemplo, Visual Studio Code, Brackets o Sublime Text).
2. Crear la Estructura del Proyecto
-
Crea una nueva carpeta llamada «unit-testing» en tu computadora usando el comando
mkdir. Aquí es donde almacenarás tus archivos de prueba. -
Abre la carpeta
unit-testingen tu editor de código y abre una ventana de terminal dentro de ella.
3. Inicializar el Proyecto e Instalar las Dependencias
Crea un archivo package.json e instala los paquetes necesarios:
npm init npm i angular --save npm i -g karma --save-dev npm i karma-jasmine jasmine-core --save-dev npm i angular-mocks --save-dev npm i karma-chrome-launcher --save-dev
4. Configurar Karma
-
En tu carpeta
unit-testing, crea dos nuevas carpetas llamadasappytest. -
Luego, dentro de la carpeta
unit-testing, crea un nuevo archivo llamadokarma.config.js. -
Abre
karma.config.jsen tu editor de código y escribekarma init. Esto inicializará un repositorio vacío con algunas configuraciones estándar. -
Se te harán una serie de preguntas sobre cómo deseas configurar Karma. Respóndelas según tus preferencias (los valores predeterminados están bien).
Pruebas de Extremo a Extremo (E2E) en AngularJS con Protractor o Cypress
Las pruebas de extremo a extremo (E2E) simulan cómo un usuario real interactuaría con tu aplicación de principio a fin. Si bien las pruebas unitarias se limitan a evaluar partes individuales del código de forma aislada, las pruebas E2E son significativas para detectar problemas que surgen cuando unes esos bloques de construcción en flujos de trabajo completos.
Por ejemplo, las pruebas unitarias podrían validar que un formulario de inicio de sesión y una consulta a la base de datos funcionen como se espera. Sin embargo, las pruebas E2E van más allá al iniciar sesión con credenciales reales, hacer clic en diferentes lugares y extraer datos reales.
En consecuencia, las pruebas E2E brindan confianza en que tu aplicación funciona sin problemas en condiciones del mundo real, encontrando brechas que caen entre las pruebas unitarias y de integración.
Beneficios de las Pruebas de Extremo a Extremo
Realizar pruebas E2E integrales proporciona varios beneficios importantes:
-
Detecta más errores desde el principio, lo que lleva a un software de mayor calidad.
-
Asegura que todos los componentes trabajen juntos sin problemas, aumentando la confianza.
-
Modela flujos de trabajo de usuarios del mundo real, mejorando la experiencia del usuario.
-
Ahorra tiempo y dinero al corregir problemas antes que después.
-
Promueve la colaboración entre equipos que trabajan en diferentes componentes.
-
Automatiza pruebas repetitivas, aumentando la productividad.
-
Acelera el tiempo de llegada al mercado al reducir defectos antes del lanzamiento.
En resumen, las pruebas E2E ofrecen un software más robusto y confiable que satisface las necesidades empresariales y de los usuarios al validar la calidad de principio a fin en toda la aplicación.
1. Configurar Cypress para Pruebas E2E
Configurar Cypress es sencillo:
-
Crea una nueva carpeta de proyecto e inicialízala:
npm init -
Instala Cypress en la carpeta del proyecto:
npm install cypress --save-dev(oyarn add cypress --dev)
¡Y eso es todo! Con Cypress instalado, ahora puedes comenzar a crear y ejecutar pruebas de extremo a extremo para tu aplicación.
2. Instalar Protractor para Pruebas E2E
Requisito previo: Node.js debe estar instalado.
-
Abre una terminal y escribe:
npm install -g protractor-
Esto instala dos herramientas de línea de comandos:
protractor(el ejecutor de pruebas) ywebdriver-manager(gestiona el controlador web de Selenium).
-
-
Verifica la instalación con:
protractor --version
Esto instalará la última versión de Protractor globalmente, haciendo que el ejecutor de pruebas y el administrador de Selenium estén disponibles desde la línea de comandos.
Pruebas de Integración en AngularJS
Las pruebas de integración validan que diferentes unidades o componentes de una aplicación funcionen correctamente cuando se combinan.
Es importante distinguir esto de otros tipos de prueba:
-
Las pruebas unitarias se centran en unidades individuales de forma aislada.
-
Las pruebas de extremo a extremo (E2E) replican flujos de trabajo completos del usuario.
Sin embargo, las pruebas de integración confirman que las interacciones entre las unidades integradas funcionan como se espera. Por ejemplo, puede probar que la capa de interfaz de usuario llame y muestre con éxito datos desde un endpoint de API.
Entonces, mientras las pruebas unitarias examinan módulos individuales y las E2E verifican flujos generales, las pruebas de integración se centran en verificar las conexiones entre componentes integrados.
Configurar una Prueba de Integración en Angular
Paso 1: Crear un Nuevo Proyecto Angular
Para crear un nuevo proyecto Angular, escribe el siguiente comando en tu terminal:
ng new angular-todo-app
Espera a que Angular configure tu nuevo proyecto.
Paso 2: Aprovechar los Archivos de Prueba Generados Automáticamente
Angular genera automáticamente archivos de prueba (*.spec.ts) para componentes TypeScript. Para nuestra prueba de integración, utilizaremos el archivo app.component.spec.ts predeterminado que Angular genera en la carpeta raíz app. Este archivo spec está conectado al principal app.component.ts y está preconfigurado para pruebas.
Paso 3: Crear y Configurar un Conjunto de Pruebas (Test Suite)
Abre app.component.specs.ts y crea un nuevo conjunto de pruebas con el siguiente código:
describe('TodoList Integration', () => { let component: AppComponent; let fixture: ComponentFixture<AppComponent>; let service: TodoService; beforeEach(async () => { await TestBed.configureTestingModule({ imports: [FormsModule], declarations: [AppComponent, TodoComponent], providers: [ { provide: TodoService, useValue: { getTasks: () => { return dummyTodos; } } } ] }).compileComponents(); fixture = TestBed.createComponent(AppComponent); component = fixture.componentInstance; service = TestBed.inject(TodoService); }); }); const dummyTodos = [ { id: 1, title: 'Todo 1', completed: false }, { id: 2, title: 'Todo 2', completed: false } ];
Esta configuración incluye una configuración de prueba asíncrona, compilación de módulos y definición de datos ficticios (dummy data).
Paso 4: Escribir la Prueba de Integración
it('should load todos from service', async(() => { fixture.detectChanges(); expect(component.todos.length).toBe(2); expect(service.getTasks()).toEqual(dummyTodos); }));
Esta prueba activa el enlace de datos y afirma que los datos del componente coinciden con los datos del servicio.
Paso 5: Ejecutar la Prueba
Para ejecutar las pruebas de integración, navega a la raíz del proyecto en una terminal y ejecuta:
ng test
O para ejecutar un archivo específico:
ng test --include app.component.spec.ts
Angular configurará el entorno de prueba y reportará los resultados.
Probar Servicios en AngularJS
Los servicios son uno de los bloques de construcción más importantes en las aplicaciones AngularJS, ya que proporcionan lógica de negocio reutilizable. Pero, ¿cómo te aseguras de que tus servicios tengan una cobertura de pruebas robusta?
Esta sección ofrece mejores prácticas para las pruebas unitarias de tus servicios para que puedas:
-
Configurar el framework de pruebas de AngularJS desde cero.
-
Simular (mock) efectivamente las dependencias con las que interactúan tus servicios.
-
Validar el comportamiento del servicio a través de especificaciones de prueba (test specs) bien estructuradas.
-
Identificar casos de uso relevantes para maximizar la cobertura.
Probar los servicios a fondo descubre fallos temprano y da confianza en que las reglas de negocio hacen cumplir la integridad de los datos.
Probar Controladores en AngularJS
Los controladores son la columna vertebral del comportamiento dinámico en las aplicaciones AngularJS, conectando la interfaz de usuario con la lógica subyacente. Por lo tanto, probar los controladores a fondo previene problemas en la interfaz en el futuro.
Un conjunto de pruebas confiable te permite simular interacciones del usuario y validar que los controladores transformen y presenten los datos correctamente.
Inyectar Servicios en Controladores AngularJS
Al realizar pruebas unitarias de controladores, necesitarás simular sus dependencias. Hay dos formas estándar de inyectar estas dependencias:
1. Array en Línea
Define un array en línea que enumere las dependencias; útil para casos simples:
angular.module('myApp') .controller('MyController', ['$scope', 'MyService', function($scope, MyService) { // ... }]);
2. Propiedad $inject
Alternativamente, establece una propiedad $inject en la función del controlador:
angular.module('myApp') .controller('MyController', MyController); MyController.$inject = ['$scope', 'MyService']; function MyController($scope, MyService) { // ... }
Ambos enfoques funcionan para simular en pruebas. La clave es enumerar las dependencias explícitamente para asegurar que se resuelvan correctamente después de la minificación del código.
Conclusión de nuestro Tutorial de Pruebas en AngularJS
¡Felicidades por completar nuestro tutorial de pruebas en AngularJS! Ahora tienes el conocimiento fundamental y las habilidades para comenzar a construir conjuntos de pruebas robustos para tus aplicaciones AngularJS.
Si bien las pruebas pueden parecer abrumadoras al principio, perseverar con ellas tiene enormes dividendos en estabilidad de la aplicación, entrega más rápida y experiencia de usuario mejorada. Recuerda aplicar las mejores prácticas de pruebas, como el aislamiento, la simulación y la organización legible de las pruebas.
Esto era solo el comienzo. Hay mucho más por explorar, como probar directivas, pruebas de regresión visual y técnicas avanzadas para escenarios de prueba complicados.
La clave es mantener una actitud positiva, comenzar a probar temprano, refactorizar regularmente y pedir ayuda cuando la necesites. Lo más importante es que la práctica continua consolidará lo que has aprendido y generará confianza real.