DEV Community

Cover image for Angular Testing with Jasmine and Karma: Complete Guide | Unit Testing, Component Testing & E2E
Md. Maruf Rahman
Md. Maruf Rahman

Posted on • Originally published at marufrahman.live

Angular Testing with Jasmine and Karma: Complete Guide | Unit Testing, Component Testing & E2E

I'll be honest—when I first started with Angular, I skipped testing. I thought it was too time-consuming, and my code worked fine without it. Then I had to refactor a large feature, and I broke three things I didn't even know existed. That's when I learned the value of good tests. They give you confidence to refactor, catch bugs before they reach production, and serve as documentation for how your code should work.

Angular provides excellent testing support out of the box with Jasmine (the testing framework) and Karma (the test runner). TestBed makes it easy to configure testing modules, mock dependencies, and test components in isolation. The testing utilities are powerful enough to test complex scenarios while being simple enough to write tests quickly.

## What is Angular Testing?

Angular Testing provides:

  • Jasmine - Behavior-driven testing framework
  • Karma - Test runner for running tests in browsers
  • TestBed - Testing utilities for configuring test modules
  • Component Testing - Test components in isolation
  • Service Testing - Test business logic and HTTP calls
  • Pipe & Directive Testing - Test custom transformations
  • Async Testing - Test asynchronous operations
  • Mocking - Mock dependencies with spies

## Component Testing

Test Angular components with TestBed:

  import { ComponentFixture, TestBed } from '@angular/core/testing';
  import { BusinessListComponent } from './business-list.component';
  import { BusinessService } from 'src/services/business.service';
  import { of } from 'rxjs';
  import { ReactiveFormsModule } from '@angular/forms';
  import { HttpClientTestingModule } from '@angular/common/http/testing';

  describe('BusinessListComponent', () => {
    let component: BusinessListComponent;
    let fixture: ComponentFixture<BusinessListComponent>;
    let businessService: jasmine.SpyObj<BusinessService>;

    beforeEach(async () => {
      const spy = jasmine.createSpyObj('BusinessService', ['GetBusinesses']);

      await TestBed.configureTestingModule({
        declarations: [BusinessListComponent],
        providers: [
          { provide: BusinessService, useValue: spy }
        ],
        imports: [ReactiveFormsModule, HttpClientTestingModule]
      }).compileComponents();

      fixture = TestBed.createComponent(BusinessListComponent);
      component = fixture.componentInstance;
      businessService = TestBed.inject(BusinessService) as jasmine.SpyObj<BusinessService>;
    });

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

    it('should load businesses on init', () => {
      const mockBusinesses = [{ id: 1, name: 'Business 1' }];
      businessService.GetBusinesses.and.returnValue(of({ data: mockBusinesses }));

      fixture.detectChanges();

      expect(businessService.GetBusinesses).toHaveBeenCalled();
      expect(component.businesses).toEqual(mockBusinesses);
    });
  });
Enter fullscreen mode Exit fullscreen mode

## Service Testing

Test Angular services:

  import { TestBed } from '@angular/core/testing';
  import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
  import { BusinessService } from './business.service';
  import { environment } from 'src/environments/environment';

  describe('BusinessService', () => {
    let service: BusinessService;
    let httpMock: HttpTestingController;

    beforeEach(() => {
      TestBed.configureTestingModule({
        imports: [HttpClientTestingModule],
        providers: [BusinessService]
      });
      service = TestBed.inject(BusinessService);
      httpMock = TestBed.inject(HttpTestingController);
    });

    afterEach(() => {
      httpMock.verify();
    });

    it('should fetch businesses', () => {
      const mockBusinesses = [{ id: 1, name: 'Business 1' }];

      service.GetBusinesses({}).subscribe(businesses => {
        expect(businesses.data).toEqual(mockBusinesses);
      });

      const req = httpMock.expectOne(`${environment.ApiUrl}business/get`);
      expect(req.request.method).toBe('POST');
      req.flush({ data: mockBusinesses });
    });
  });
Enter fullscreen mode Exit fullscreen mode

## Best Practices

  1. Write tests for each component, service, pipe, and directive
  2. Use TestBed for component and service testing
  3. Mock dependencies with Jasmine spies
  4. Use HttpClientTestingModule for HTTP testing
  5. Test both success and error scenarios
  6. Use fakeAsync and tick for async operations
  7. Maintain high test coverage (aim for 80%+)

## 📖 Read the Complete Guide

This is just a brief overview! The complete guide on my blog includes:

  • Testing Component Inputs and Outputs - Complete examples
  • Testing Component Forms - Form validation testing
  • Pipe Testing - Testing custom pipes
  • Directive Testing - Testing custom directives
  • Async Testing - fakeAsync, tick, flush, and Observable testing
  • Testing Guards - Route guard testing
  • Testing Interceptors - HTTP interceptor testing
  • Testing RxJS Operators - Testing reactive code
  • Common Testing Patterns - Test helpers, mock factories, data builders
  • Karma Configuration - Complete setup guide
  • Real-world examples from production applications

👉 Read the full article with all code examples here


What's your experience with Angular Testing? Share your tips in the comments! 🚀

For more Angular guides, check out my blog covering Services, Component Communication, Reactive Forms, and more.

Top comments (0)