Inicio Blog Acerca de
Cómo las Pruebas Unitarias Transforman tus Aplicaciones Angular

Cómo las Pruebas Unitarias Transforman tus Aplicaciones Angular

9 min de lectura angular unit-testing testing best-practices
Tabla de Contenidos

Las pruebas unitarias son una parte esencial del desarrollo de software, junto con las Pruebas End-to-End (E2E) y las Pruebas de Integración. Juega un papel clave en garantizar la calidad de nuestra aplicación. Para los desarrolladores de software, este puede ser uno de los aspectos más desafiantes de Angular. Implica simular profundamente cómo opera Angular, comprender el funcionamiento de la Inyección de Dependencias, los Ciclos de Vida de Angular y cómo simular (mockear) servicios. Inicialmente, entender y crear una buena prueba unitaria puede ser bastante difícil.

Pirámide de Pruebas

Pirámide de Pruebas

El objetivo de la pirámide de pruebas es optimizar la cantidad de pruebas rápidas y económicas (pruebas unitarias) mientras se reduce la frecuencia de pruebas más lentas y costosas (pruebas E2E). Este enfoque no solo mejora la eficiencia de las pruebas, sino que también facilita la identificación rápida de problemas. En esencia, la pirámide de pruebas sirve como un marco estratégico para asignar efectiva y eficientemente los recursos de prueba, asegurando así la calidad del software de manera escalable.

Pero, ¿Por qué son importantes las Pruebas Unitarias?

  • Encontrar errores temprano: Las pruebas unitarias te permiten detectar errores en tu código mientras lo creas, por lo que es más fácil corregirlos antes de que los usuarios se vean afectados.

  • Hacer mejor código: Escribir pruebas unitarias te hace pensar sobre cómo funciona tu código y ayuda a asegurar que esté bien hecho.

  • Refactorizar de forma segura: Las pruebas unitarias te dan confianza de que puedes cambiar tu código sin causar problemas.

  • Aumentar la cobertura de código: La cobertura de código es el porcentaje de código que ejecutan las pruebas unitarias. Una alta cobertura de código muestra que tu código está bien probado (Y ahí es donde radica la importancia de hacer una buena Prueba Unitaria).

¿Qué herramientas tienes para hacer pruebas unitarias en Angular?

Angular tiene herramientas integradas para pruebas unitarias. Las principales son:

  • Karma: Un ejecutor de pruebas que ejecuta pruebas unitarias en el navegador.

  • Jasmine: Un framework para escribir pruebas unitarias.

  • TestBed: Un módulo que te ayuda a configurar un entorno de pruebas para tu componente.

  • Jest: Un framework para escribir pruebas en el navegador y puede usarse en reemplazo de Karma.

¿Qué hace que una prueba sea una buena Prueba Unitaria?

Algunas prácticas recomendadas para realizar una Prueba Unitaria incluyen:

  • Arrange, Act, Assert (AAA)

    • Arrange: Esta es la configuración para que nuestra prueba tenga todo lo que necesita para funcionar.

    • Act: Ejecutar la acción

    • Assert: Verificar el resultado del Act.

  • Aislar el componente a probar

  • Para componentes que dependen de servicios para su comportamiento, usar "Test Doubles" (mocks, stubs, doubles).

  • Usar spies para verificar el comportamiento de métodos o funciones.

  • Siempre usar datos Mock. Esto hace que las pruebas sean predecibles.

  • Usar un buen nombre para la Prueba Unitaria.

  • Probar las interacciones esperadas: Haz clic en nuestros botones, no llames a los métodos directamente

it('should emit form value when the user clicks the button and form is valid', async () => {
      const expectedEmittedQueryValue = 'test';
      component.form.setValue({ query: expectedEmittedQueryValue });
      component.form.markAsTouched();

      // Spies
      const submitSpy = jest.spyOn(component, 'submitForm');
      const outputSpy = jest.spyOn(component.query, 'emit');

      // Find the button
      const button = de.nativeElement.querySelector(
        '[data-testId="submit-button"]'
      );

      // Always check the null
      expect(button).not.toBeNull();

      // Simulate the click of the user at the button
      button.click();

      expect(component.form.valid).toBe(true);
      expect(submitSpy).toHaveBeenCalled();
      expect(outputSpy).toHaveBeenCalledWith(expectedEmittedQueryValue);
    });
  • Encuentra elementos con data-testId, no con clases CSS.
 <span
    data-testId="reset-icon"
    nz-icon
    class="ant-input-clear-icon"
    nzTheme="fill"
    nzType="close-circle"
    (click)="resetForm()">
</span>
it('form should be reset when click clear icon', async () => {
        // Add something to the form
        component.form.setValue({ query: 'test' });
        fixture.detectChanges();

        await fixture.whenStable();

        // Use the data-testId not the class name of the element
        const clearIcon = de.nativeElement.querySelector(
          '[data-testId="reset-icon"]'
        );
        // Check the null
        expect(clearIcon).not.toBeNull();

        // Act
        jest.spyOn(component, 'resetForm'); // Spi the method
        clearIcon.click(); // Simulate the click the element

        // Assert
        expect(component.resetForm).toHaveBeenCalled();
        expect(component.form.controls['query'].value).toBeNull();
      });
  • Probar todos los caminos de código posibles (tanto verdadero como falso)
it('should show loading button when input is loading `true`', () => {
      // arrange
      const button = fixture.debugElement.query(
        By.directive(NzButtonComponent);
      expect(button).not.toBeNull();

      // checking the false
      fixture.componentRef.setInput('isLoading', false);
      fixture.detectChanges();

      // assert
      expect(button.injector.get(NzButtonComponent).nzLoading).toBe(false);

      // checking the true
      fixture.componentRef.setInput('isLoading', true);
      fixture.detectChanges();

      // assert
      expect(button.injector.get(NzButtonComponent).nzLoading).toBe(true);
    });
  • Mockear un servicio usado en un componente para verificar el mensaje mostrado en el componente
describe('UserComponent', () => {
  let component: UserComponent;
  let fixture: ComponentFixture<UserComponent>;
  let userServiceMock: Partial<UserService>;

  beforeEach(async () => {
    // create a mock of the service
    userServiceMock = {
      isLoggedIn: jest.fn(),
    };

    await TestBed.configureTestingModule({
      declarations: [UserComponent],

      // Replace the UserService with the mock
      providers: [{ provide: UserService, useValue: userServiceMock }],
    }).compileComponents();

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

  it('should show "Logged In" if the user is logged in', () => {
    // manipulate the value of isLoggedIn to return true
    userServiceMock.isLoggedIn.mockReturnValue(true);
    fixture.detectChanges();
    expect(component.message).toBe('Logged In');
  });

  it('should show "Not Logged In" if the user is not logged in', () => {
    // manipulate the value of isLoggedIn to return false
    userServiceMock.isLoggedIn.mockReturnValue(false);
    fixture.detectChanges();
    expect(component.message).toBe('Not Logged In');
  });
});

Qué otras herramientas uso para Pruebas Unitarias

  1. Spectator: Simplifica las pruebas de Angular eliminando tareas repetitivas, haciendo que las pruebas unitarias sean claras y eficientes. Permite probar componentes, directivas, servicios y más sin necesitar un conocimiento profundo de las APIs TestBed, ComponentFixture y DebugElement. Las características incluyen consulta simple del DOM, activación de eventos, soporte de pruebas de enrutamiento y HTTP, auto-mocking de proveedores y compatibilidad con Jest.

  2. NgMock: Esta es una biblioteca para Angular que simplifica la creación de mocks en pruebas, permitiendo la simulación de componentes, directivas, pipes, servicios, módulos y tokens. Facilita la configuración de TestBed, reduce el código repetitivo en las pruebas y ofrece una interfaz simple para acceder a las declaraciones. Compatible con varias versiones de Angular, NgMocks soporta tanto Jasmine como Jest, ayudando a crear un entorno de pruebas más eficiente y menos tedioso.

Conclusión

En conclusión, las pruebas unitarias son cruciales para crear aplicaciones Angular robustas y confiables. Permiten a los desarrolladores detectar errores temprano, mejorar la calidad del código, asegurar una refactorización segura y lograr alta cobertura de código. Con las herramientas de Angular como Karma, Jasmine, TestBed y opcionalmente Jest, los desarrolladores pueden seguir las mejores prácticas como Arrange, Act, Assert (AAA), aislamiento de componentes, uso de test doubles y prueba de todos los caminos de código. Estas estrategias conducen a aplicaciones funcionales, mantenibles y escalables, mejorando la calidad del software y el proceso de desarrollo.

Logo
Arcadio QuinteroSystems Engineer

Compartiendo conocimiento práctico sobre arquitectura de software, mejores prácticas de Angular y el panorama evolutivo del desarrollo web.

© 2026 Arcadio Quintero. Todos los derechos reservados.

Construido conAnalog&Angular