On this page
Testing
Angular ships with Jasmine (assertion framework) and Karma (test runner). Use TestBed to configure and instantiate components in isolation.
Running Tests
ng test # Karma + browser
ng test --watch=false # Single run (CI)
ng test --code-coverage # Coverage report
New projects include a .spec.ts file alongside each component.
Testing a Service
import { TestBed } from '@angular/core/testing';
import { UserService } from './user.service';
describe('UserService', () => {
let service: UserService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(UserService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
it('should return users', () => {
const users = service.getUsers();
expect(users.length).toBeGreaterThan(0);
expect(users[0].name).toBeDefined();
});
it('should add a user', () => {
const initialCount = service.getUsers().length;
service.addUser({ name: 'Charlie', email: '[email protected]' });
expect(service.getUsers().length).toBe(initialCount + 1);
});
});
Testing a Component
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { CounterComponent } from './counter.component';
describe('CounterComponent', () => {
let component: CounterComponent;
let fixture: ComponentFixture<CounterComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [CounterComponent] // Standalone component
}).compileComponents();
fixture = TestBed.createComponent(CounterComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should display initial count', () => {
const el = fixture.nativeElement as HTMLElement;
expect(el.textContent).toContain('Count: 0');
});
it('should increment on button click', () => {
const button = fixture.nativeElement.querySelector('button')!;
button.click();
fixture.detectChanges();
expect(component.count()).toBe(1);
expect(fixture.nativeElement.textContent).toContain('Count: 1');
});
});
Mocking Dependencies
Replace real services with test doubles:
import { of } from 'rxjs';
const mockPostService = {
getPosts: () => of([
{ id: 1, title: 'Test Post', body: 'Body' }
])
};
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [PostListComponent],
providers: [
{ provide: PostService, useValue: mockPostService }
]
}).compileComponents();
});
Testing HTTP
Use HttpClientTestingModule to mock API calls:
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
describe('PostService', () => {
let service: PostService;
let httpMock: HttpTestingController;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [PostService]
});
service = TestBed.inject(PostService);
httpMock = TestBed.inject(HttpTestingController);
});
afterEach(() => {
httpMock.verify(); // No outstanding requests
});
it('should fetch posts', () => {
service.getPosts().subscribe(posts => {
expect(posts.length).toBe(1);
expect(posts[0].title).toBe('Hello');
});
const req = httpMock.expectOne('https://api.example.com/posts');
expect(req.request.method).toBe('GET');
req.flush([{ id: 1, title: 'Hello', body: 'World' }]);
});
});
Write tests for services and complex components first. Test behavior through the DOM, call fixture.detectChanges() after updates, and mock dependencies with useValue providers.