Unit testing in Angular focuses on verifying that individual building blocks like components, services, and pipes work correctly in isolation. Angular uses Jasmine for writing test specs and Karma as the test runner that executes these tests in a browser.
Well-written unit tests make your Angular app more reliable, easier to refactor, and safer to extend with new features.
describe()): Groups related tests together.it()): A single test that checks one behavior.expect()): Asserts the actual result against the expected result.At the core of Angular unit testing is the combination of Jasmine’s BDD-style syntax and Angular’s TestBed utility:
describe() defines a test suite (what is being tested).beforeEach() sets up the test environment before every test.it() defines an individual spec (a single behavior or rule).expect() creates an assertion about how the code should behave.TestBed.configureTestingModule() configures an Angular testing module for your tests.
// Basic Jasmine test structure with Angular
import { TestBed } from '@angular/core/testing';
import { MyService } from './my.service';
describe('MyService', () => {
let service: MyService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(MyService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});
Services usually contain business logic or data-fetching logic. Unit tests for services verify that the exposed methods return the expected values.
// data.service.ts - service that returns sample data
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class DataService {
getData(): string {
return 'Hello Angular';
}
}
// data.service.spec.ts - unit tests for DataService
import { TestBed } from '@angular/core/testing';
import { DataService } from './data.service';
describe('DataService', () => {
let service: DataService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(DataService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
it('should return correct data', () => {
expect(service.getData()).toBe('Hello Angular');
});
});
Components combine template + logic. In unit tests, we often verify that the component class behaves correctly and that the template reflects the class state.
// app.component.ts - simple component with a title
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: '<h1>{{ title }}</h1>'
})
export class AppComponent {
title = 'Unit Testing Demo';
}
// app.component.spec.ts - unit tests for AppComponent
import { ComponentFixture, TestBed } 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('should create the app', () => {
expect(component).toBeTruthy();
});
it('should have title "Unit Testing Demo"', () => {
expect(component.title).toBe('Unit Testing Demo');
});
});
.spec.ts).TestBed.configureTestingModule().DataService using TestBed.inject().getData() returns 'Hello Angular'.AppComponent declared.ComponentFixture to host the component in a test environment.title property matches the expected text.@Input() properties and write tests to verify that input values are rendered correctly in the template.AppComponent (e.g., subtitle) and extend the tests to verify both title and subtitle.