Pruebas y Depuración

Capítulo 11: Pruebas y Depuración

Compartir

La calidad de una aplicación Angular es esencial, por lo que es importante realizar pruebas y depuración de manera efectiva. En este capítulo, exploraremos las estrategias de prueba en Angular, las técnicas de depuración y los tipos de pruebas que puedes realizar.

11.1 Estrategias de Prueba en Angular

Las estrategias de prueba son esenciales para garantizar que tu aplicación Angular funcione correctamente. Algunas de las estrategias clave incluyen:

  • Pruebas Unitarias: Estas pruebas se centran en verificar el comportamiento de componentes individuales o servicios. Se pueden realizar con herramientas como Jasmine y Karma.

A continuación, te proporcionaré un ejemplo de prueba unitaria utilizando Jasmine en el contexto de una aplicación de comercio electrónico en Angular. Supongamos que estamos probando una función que calcula el total de un carrito de compras.

Paso 1: Función a Probar (cart.service.ts):

export class CartService {
  items: any[] = [];

  addToCart(product: any) {
    this.items.push(product);
  }

  getCartTotal() {
    return this.items.reduce((total, product) => total + product.price, 0);
  }
}

Paso 2: Prueba Unitaria (cart.service.spec.ts):

import { CartService } from './cart.service';

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

  beforeEach(() => {
    service = new CartService();
  });

  it('should be created', () => {
    expect(service).toBeTruthy();
  });

  it('should add a product to the cart', () => {
    const product = { name: 'Product 1', price: 10 };
    service.addToCart(product);
    expect(service.items.length).toBe(1);
  });

  it('should calculate the cart total', () => {
    const product1 = { name: 'Product 1', price: 10 };
    const product2 = { name: 'Product 2', price: 20 };
    service.addToCart(product1);
    service.addToCart(product2);
    expect(service.getCartTotal()).toBe(30);
  });
});

En este ejemplo, hemos creado pruebas unitarias para el servicio de carrito (CartService) de una aplicación de comercio electrónico. Hemos utilizado Jasmine para escribir las pruebas. Aquí hay una breve descripción de las pruebas:

  1. should be created: Verifica si el servicio se crea correctamente.
  2. should add a product to the cart: Comprueba si la función addToCart agrega un producto al carrito y si la longitud del carrito es 1 después de agregar un producto.
  3. should calculate the cart total: Evalúa si la función getCartTotal calcula correctamente el total del carrito después de agregar dos productos con precios diferentes.

Estas pruebas unitarias aseguran que las funciones del servicio de carrito funcionen como se esperaba. Debes ejecutar las pruebas utilizando una herramienta de prueba como Karma para garantizar que la lógica de tu aplicación de comercio electrónico sea sólida y libre de errores.

  • Pruebas de Integración: Verifican cómo los diferentes componentes y servicios interactúan entre sí. Puedes usar Jasmine y Karma para estas pruebas.

Las pruebas de integración en Angular generalmente se centran en cómo los diferentes componentes y servicios interactúan entre sí en una aplicación. En este ejemplo, vamos a realizar una prueba de integración para un componente de carrito de compras (CartComponent) que se comunica con el servicio de carrito (CartService) en una aplicación de comercio electrónico.

Paso 1: Componente de Carrito de Compras (cart.component.ts):

import { Component } from '@angular/core';
import { CartService } from './cart.service';

@Component({
  selector: 'app-cart',
  templateUrl: './cart.component.html',
})
export class CartComponent {
  items: any[] = [];

  constructor(private cartService: CartService) {}

  ngOnInit() {
    this.items = this.cartService.getCartItems();
  }
}

Paso 2: Servicio de Carrito de Compras (cart.service.ts):

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root',
})
export class CartService {
  items: any[] = [];

  addToCart(product: any) {
    this.items.push(product);
  }

  getCartItems() {
    return this.items;
  }
}

Paso 3: Prueba de Integración (cart.component.spec.ts):

import { ComponentFixture, TestBed } from '@angular/core/testing';
import { CartComponent } from './cart.component';
import { CartService } from './cart.service';
import { DebugElement } from '@angular/core';
import { By } from '@angular/platform-browser';

describe('CartComponent', () => {
  let component: CartComponent;
  let fixture: ComponentFixture<CartComponent>;
  let cartService: CartService;
  let debugElement: DebugElement;

  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [CartComponent],
      providers: [CartService],
    });
    fixture = TestBed.createComponent(CartComponent);
    component = fixture.componentInstance;
    cartService = TestBed.inject(CartService);
    debugElement = fixture.debugElement;
  });

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

  it('should fetch cart items from the service', () => {
    const testItems = [{ name: 'Product 1', price: 10 }, { name: 'Product 2', price: 20 }];
    spyOn(cartService, 'getCartItems').and.returnValue(testItems);
    fixture.detectChanges();

    const itemElements = debugElement.queryAll(By.css('.cart-item'));
    expect(itemElements.length).toBe(testItems.length);
  });
});

En este ejemplo, hemos escrito una prueba de integración para el componente CartComponent. La prueba verifica dos cosas:

  1. should create: Asegura que el componente se cree correctamente.
  2. should fetch cart items from the service: Verifica si el componente se comunica adecuadamente con el servicio CartService para obtener los elementos del carrito y los muestra en la vista.

Hemos utilizado Jasmine junto con TestBed y Angular testing utilities como DebugElement y By para realizar la prueba de integración. Esto garantiza que el componente se integre adecuadamente con el servicio y muestre los elementos del carrito en la vista.

  • Pruebas End-to-End: Estas pruebas evalúan cómo funciona la aplicación desde la perspectiva del usuario final. Protractor es una herramienta comúnmente utilizada para pruebas end-to-end en Angular.

Las pruebas end-to-end (E2E) con Protractor son esenciales para asegurarse de que una aplicación de comercio electrónico funcione correctamente desde la perspectiva del usuario final. A continuación, te proporcionaré un ejemplo simplificado de una prueba E2E utilizando Protractor en una aplicación de comercio electrónico.

Paso 1: Configuración de Protractor (protractor.conf.js):

exports.config = {
  framework: 'jasmine',
  seleniumAddress: 'http://localhost:4444/wd/hub',
  specs: ['e2e/**/*.e2e-spec.js'],
  capabilities: {
    browserName: 'chrome',
  },
};

Paso 2: Especificación de Prueba E2E (e2e/cart.e2e-spec.js):

describe('Carrito de Compras', () => {
  it('debería agregar un producto al carrito', () => {
    browser.get('/'); // Navega a la página principal de la aplicación

    const addToCartButton = element(by.css('.product .add-to-cart-button'));
    addToCartButton.click(); // Haz clic en el botón "Agregar al carrito"

    const cartIcon = element(by.css('.cart-icon'));
    cartIcon.click(); // Abre el carrito de compras

    const cartItems = element.all(by.css('.cart-item'));
    expect(cartItems.count()).toBe(1); // Verifica que haya un producto en el carrito
  });

  it('debería realizar el proceso de compra', () => {
    browser.get('/'); // Navega a la página principal de la aplicación

    const addToCartButton = element(by.css('.product .add-to-cart-button'));
    addToCartButton.click(); // Haz clic en el botón "Agregar al carrito"

    const checkoutButton = element(by.css('.cart .checkout-button'));
    checkoutButton.click(); // Haz clic en el botón "Pagar"

    const paymentMethodInput = element(by.css('input[name="paymentMethod"]'));
    paymentMethodInput.sendKeys('Tarjeta de Crédito'); // Completa el método de pago

    const placeOrderButton = element(by.css('.checkout .place-order-button'));
    placeOrderButton.click(); // Haz clic en el botón "Realizar Pedido"

    const orderConfirmationMessage = element(by.css('.order-confirmation'));
    expect(orderConfirmationMessage.isPresent()).toBe(true); // Verifica la confirmación del pedido
  });
});

En este ejemplo, hemos definido dos pruebas E2E utilizando Protractor. La primera prueba verifica si se puede agregar un producto al carrito y si el carrito se actualiza correctamente. La segunda prueba simula un proceso de compra, incluida la selección de un método de pago y la confirmación del pedido.

Asegúrate de que tu configuración de Protractor esté correctamente alineada con la estructura de tu aplicación y ajusta las rutas y selectores CSS según corresponda.

Para ejecutar estas pruebas, debes asegurarte de que la aplicación esté en ejecución y que el servidor Selenium esté activo. Luego, puedes ejecutar las pruebas utilizando el comando protractor protractor.conf.js. Protractor abrirá una instancia de Chrome y automatizará las acciones especificadas en las pruebas.

Ten en cuenta que este es un ejemplo simplificado y que en una aplicación de comercio electrónico real, las pruebas E2E pueden ser más complejas y cubrir más escenarios de usuario.

  • Pruebas de Aceptación: Estas pruebas se centran en verificar que la aplicación cumple con los requisitos del usuario. Puedes utilizar herramientas como Cucumber o Jasmine para escribir pruebas de aceptación.

Las pruebas de aceptación con Cucumber son una forma de escribir pruebas utilizando un lenguaje natural que describe el comportamiento esperado de una aplicación. Aquí tienes un ejemplo simplificado de una prueba de aceptación utilizando Cucumber enfocada en una funcionalidad de búsqueda de productos en una aplicación de comercio electrónico.

Paso 1: Definición de Escenarios (buscar-productos.feature):

Feature: Búsqueda de productos
  Como usuario
  Quiero buscar productos en la aplicación
  Para encontrar productos de mi interés

  Scenario: Búsqueda exitosa de un producto
    Given Estoy en la página de inicio
    When Ingreso "zapatos" en el campo de búsqueda
    And Presiono el botón de búsqueda
    Then Debería ver una lista de productos relacionados

  Scenario: Búsqueda sin resultados
    Given Estoy en la página de inicio
    When Ingreso "producto_inexistente" en el campo de búsqueda
    And Presiono el botón de búsqueda
    Then Debería ver un mensaje de "No se encontraron resultados"

Paso 2: Implementación de los Pasos de los Escenarios (buscar-productos.steps.ts):

import { Given, When, Then, And } from 'cucumber';
import { browser, element, by } from 'protractor';
import { expect } from 'chai';

Given('Estoy en la página de inicio', async () => {
  await browser.get('/');
});

When('Ingreso {string} en el campo de búsqueda', async (searchTerm) => {
  const searchInput = element(by.css('input[name="search"]'));
  await searchInput.sendKeys(searchTerm);
});

And('Presiono el botón de búsqueda', async () => {
  const searchButton = element(by.css('button[name="search-button"]'));
  await searchButton.click();
});

Then('Debería ver una lista de productos relacionados', async () => {
  const productResults = element.all(by.css('.product'));
  expect(await productResults.count()).to.be.greaterThan(0);
});

Then('Debería ver un mensaje de {string}', async (message) => {
  const noResultsMessage = element(by.css('.no-results-message'));
  expect(await noResultsMessage.getText()).to.equal(message);
});

Paso 3: Ejecución de las Pruebas:

Para ejecutar las pruebas de aceptación, necesitas configurar Cucumber y Protractor. Asegúrate de que tu aplicación esté en ejecución y el servidor Selenium esté activo. Luego, puedes ejecutar las pruebas utilizando el comando adecuado, como protractor cucumberConf.js.

Ten en cuenta que este es un ejemplo simplificado de pruebas de aceptación con Cucumber. En una aplicación de comercio electrónico real, tendrás escenarios más complejos y varios pasos que describen el comportamiento del usuario. Las pruebas de aceptación son una forma efectiva de comunicar y validar los requisitos funcionales de la aplicación en un lenguaje comprensible para todas las partes interesadas.

11.2 Depuración de la Aplicación

La depuración es esencial para encontrar y solucionar errores en tu aplicación Angular. Algunas técnicas de depuración incluyen:

  • Consola del Navegador: Utiliza console.log y otras funciones de la consola para registrar mensajes de depuración en la consola del navegador.

La depuración de una aplicación Angular a través de la consola del navegador es una de las técnicas más comunes para encontrar y solucionar errores. A continuación, te proporcionaré un ejemplo simple de cómo puedes usar la consola del navegador para depurar tu aplicación Angular.

Paso 1: Código de la Aplicación (app.component.ts):

Supongamos que tienes un componente en tu aplicación Angular que muestra una lista de productos. Sin embargo, hay un error en el código que deseas depurar. Aquí tienes un componente de ejemplo con un error:

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
    <h1>Lista de Productos</h1>
    <ul>
      <li *ngFor="let product of products">{{ product.name }}</li>
    </ul>
  `,
})
export class AppComponent {
  products: any[] = null; // Simulamos un error: products no está inicializado

  constructor() {
    this.fetchProducts(); // Método para obtener la lista de productos (simulado)
  }

  fetchProducts() {
    // Simulamos una solicitud HTTP para obtener la lista de productos
    setTimeout(() => {
      this.products = [
        { id: 1, name: 'Producto 1' },
        { id: 2, name: 'Producto 2' },
        { id: 3, name: 'Producto 3' },
      ];
    }, 2000);
  }
}

En este ejemplo, hemos introducido un error al no inicializar la variable products. Esto provocará un error de «Cannot read property ‘name’ of null» en la plantilla.

Paso 2: Depuración con la Consola del Navegador:

  1. Abre tu aplicación Angular en el navegador (por ejemplo, Google Chrome).
  2. Abre las herramientas de desarrollo del navegador (generalmente puedes hacerlo presionando F12 o haciendo clic derecho en la página y seleccionando «Inspeccionar» o «Iniciar herramientas para desarrolladores»).
  3. Ve a la pestaña «Consola» en las herramientas de desarrollo.
  4. Observa el error que aparece en la consola, que debería ser similar a «Cannot read property ‘name’ of null».
  5. Haz clic en el enlace del archivo y la línea del error para ir directamente al código fuente donde ocurrió el error.
  6. En este caso, podrás ver que el error se produce en la línea {{ product.name }}. Puedes identificar que products no se inicializó correctamente.
  7. Para corregir el error, asegúrate de inicializar products en el constructor o en otro lugar apropiado antes de usarlo en la plantilla.
  8. Vuelve a cargar la página y verifica que el error se haya solucionado.

La consola del navegador es una herramienta valiosa para depurar errores en tu aplicación Angular. Te permite ver mensajes de error, registros de variables y seguir el flujo de ejecución de tu código para identificar y solucionar problemas de manera eficaz.

  • Depurador del Navegador: Las herramientas de desarrollo de los navegadores modernos, como Chrome DevTools, permiten establecer puntos de interrupción, inspeccionar variables y seguir el flujo de ejecución del código.

La depuración de una aplicación Angular utilizando el depurador del navegador, como Chrome DevTools, es una técnica eficaz para rastrear y solucionar problemas en el código. A continuación, te proporcionaré un ejemplo de cómo puedes utilizar el depurador del navegador para depurar tu aplicación Angular.

Paso 1: Código de la Aplicación (app.component.ts):

Supongamos que tienes un componente en tu aplicación Angular que muestra una lista de productos. Sin embargo, hay un error en el código que deseas depurar. Aquí tienes un componente de ejemplo con un error:

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
    <h1>Lista de Productos</h1>
    <ul>
      <li *ngFor="let product of products">{{ product.name }}</li>
    </ul>
  `,
})
export class AppComponent {
  products: any[] = null; // Simulamos un error: products no está inicializado

  constructor() {
    this.fetchProducts(); // Método para obtener la lista de productos (simulado)
  }

  fetchProducts() {
    // Simulamos una solicitud HTTP para obtener la lista de productos
    setTimeout(() => {
      this.products = [
        { id: 1, name: 'Producto 1' },
        { id: 2, name: 'Producto 2' },
        { id: 3, name: 'Producto 3' },
      ];
    }, 2000);
  }
}

En este ejemplo, hemos introducido un error al no inicializar la variable products. Esto provocará un error de «Cannot read property ‘name’ of null» en la plantilla.

Paso 2: Depuración con el Depurador del Navegador (Chrome DevTools):

  1. Abre tu aplicación Angular en Google Chrome.
  2. Abre las herramientas de desarrollo del navegador (generalmente puedes hacerlo presionando F12 o haciendo clic derecho en la página y seleccionando «Inspeccionar» o «Iniciar herramientas para desarrolladores»).
  3. Ve a la pestaña «Sources» (Fuentes) en las herramientas de desarrollo.
  4. Encuentra el archivo TypeScript correspondiente a tu componente. En este caso, sería «app.component.ts».
  5. Localiza la línea donde se produce el error. En este ejemplo, deberías ver el error en la línea {{ product.name }}.
  6. Establece un punto de interrupción (breakpoint) en la línea donde deseas detener la ejecución del código. Para hacerlo, haz clic en el número de línea a la izquierda de la fuente de código.
  7. Refresca la página o navega a la parte de la aplicación donde ocurre el error. La ejecución se detendrá en el punto de interrupción.
  8. Utiliza las herramientas del depurador para inspeccionar variables, seguir el flujo de ejecución y encontrar la causa del error. Puedes ver el valor de las variables y utilizar la consola para realizar evaluaciones.
  9. Corrige el error, en este caso, asegurándote de inicializar products correctamente.
  10. Continúa la ejecución (puedes hacerlo con los botones de control en el depurador, como «Play» o «Step Over») y verifica que el error se haya solucionado.

El depurador del navegador te permite inspeccionar el estado de tu aplicación en tiempo real y resolver problemas de manera eficiente. Puedes seguir el flujo de ejecución, inspeccionar variables y tomar medidas para corregir errores.

  • Extensiones de Depuración: Puedes utilizar extensiones de terceros como Augury para depurar aplicaciones Angular específicamente.

Augury es una extensión de depuración para aplicaciones Angular que proporciona una visión detallada de la estructura y el estado de una aplicación. A continuación, te mostraré un ejemplo de cómo usar Augury para depurar una aplicación Angular.

Paso 1: Instalación de Augury:

Asegúrate de tener Augury instalado en tu navegador. Puedes encontrar la extensión Augury en la tienda de extensiones de Chrome.

Paso 2: Uso de Augury para la Depuración:

Supongamos que tienes una aplicación Angular con un componente llamado ProductListComponent que muestra una lista de productos. Si deseas depurar este componente, sigue estos pasos:

  1. Abre tu aplicación Angular en el navegador Google Chrome.
  2. Abre las herramientas de desarrollo del navegador (generalmente puedes hacerlo presionando F12 o haciendo clic derecho en la página y seleccionando «Inspeccionar» o «Iniciar herramientas para desarrolladores»).
  3. En la barra de herramientas de las herramientas de desarrollo, selecciona la pestaña «Augury».
  4. En la pestaña «Augury», encontrarás una representación de la estructura de tu aplicación Angular. Puedes navegar por los componentes y módulos de la aplicación.
  5. Selecciona el componente que deseas depurar. En este caso, elige «ProductListComponent».
  6. Augury te mostrará información detallada sobre el componente seleccionado, incluyendo su estructura de datos, propiedades, eventos, directivas y más.
  7. Puedes usar Augury para inspeccionar las propiedades y estados del componente, lo que facilita la identificación de problemas y la comprensión de cómo se comporta la aplicación.
  8. Además, Augury proporciona herramientas para ver y depurar el estado de la tienda si estás utilizando NgRx o Redux en tu aplicación.
  9. Utiliza las capacidades de Augury para inspeccionar la estructura y el estado de tu aplicación Angular y depurar problemas de manera más eficiente.

Augury es una herramienta poderosa para depurar aplicaciones Angular, ya que ofrece una vista detallada de la estructura y el estado de la aplicación, lo que facilita la identificación y solución de problemas. Puedes explorar componentes, propiedades, eventos y más, lo que te ayuda a comprender y depurar tu aplicación de manera efectiva.

11.3 Pruebas Unitarias y de Integración

Aunque ya mencionamos este tema quiero nombrar algunas de las pruebas unitarias y de integración que son fundamentales en el desarrollo de aplicaciones Angular. Algunos conceptos clave en este contexto son:

  • Jasmine: Un popular framework de pruebas para JavaScript utilizado en Angular.
  • Karma: Una herramienta de automatización de pruebas que se integra bien con Jasmine y permite ejecutar pruebas en múltiples navegadores.
  • TestBed: Utilizado para configurar el entorno de pruebas en Angular, proporcionando un módulo de prueba y servicios falsos.
  • Herramientas de Aserciones: Jasmine ofrece un conjunto de funciones de aserciones como expect para verificar resultados esperados en pruebas.

11.4 Pruebas End-to-End con Protractor

Protractor es una herramienta popular para realizar pruebas end-to-end en aplicaciones Angular. Algunos conceptos importantes incluyen:

  • Configuración de Protractor: Definir archivos de configuración para especificar las ubicaciones de las pruebas y las configuraciones de los navegadores.
  • Especificaciones de Pruebas: Escribir especificaciones de pruebas utilizando la sintaxis de Protractor para interactuar con la aplicación como un usuario real.
  • Localizadores: Utilizar selectores y localizadores para identificar elementos en la aplicación que deben ser probados.
  • Ejecución de Pruebas: Ejecutar las pruebas de Protractor y analizar los resultados para identificar problemas.

Realizar pruebas y depuración en Angular es un aspecto fundamental del desarrollo de aplicaciones de calidad. Con las herramientas y estrategias adecuadas, puedes garantizar que tu aplicación funcione sin problemas y cumpla con los requisitos del usuario.


Compartir

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *