Testing Services
Services are the most straightforward units to test. TestBed provides dependency injection for isolated testing.
Basic Service Test
import { TestBed } from '@angular/core/testing';
import { UserService } from './user.service';
import { HttpClient } from '@angular/common/http';
import { of } from 'rxjs';
describe('UserService', () => {
let service: UserService;
let httpMock: jasmine.SpyObj<HttpClient>;
beforeEach(() => {
// Create a spy object for HttpClient
httpMock = jasmine.createSpyObj('HttpClient', ['get', 'post', 'put', 'delete']);
TestBed.configureTestingModule({
providers: [
UserService,
{ provide: HttpClient, useValue: httpMock },
],
});
service = TestBed.inject(UserService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
it('should fetch users', () => {
const mockUsers: User[] = [
{ id: 1, name: 'Alice', email: 'alice@example.com' },
];
httpMock.get.and.returnValue(of(mockUsers));
service.getUsers().subscribe(users => {
expect(users).toEqual(mockUsers);
});
expect(httpMock.get).toHaveBeenCalledWith('/api/users');
});
});
Overriding Providers
TestBed.configureTestingModule({
providers: [
UserService,
{ provide: HttpClient, useValue: mockHttp },
{ provide: AuthService, useValue: mockAuth },
],
});
Jasmine Spies
it('should call the API', () => {
const spy = spyOn(httpMock, 'get').and.returnValue(of([]));
service.getUsers().subscribe();
expect(spy).toHaveBeenCalledWith('/api/users');
});
Testing Async Service Code
Services often return Observables. Use fakeAsync and tick for deterministic async testing.
fakeAsync and tick
import { fakeAsync, tick, TestBed } from '@angular/core/testing';
describe('UserService with fakeAsync', () => {
let service: UserService;
beforeEach(() => {
TestBed.configureTestingModule({
providers: [UserService],
});
service = TestBed.inject(UserService);
});
it('should fetch users after delay', fakeAsync(() => {
let users: User[] = [];
service.getUsers().subscribe(result => {
users = result;
});
tick(1000); // Advance virtual time by 1000ms
expect(users.length).toBe(2);
}));
});
Testing with HttpTestingController
import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing';
import { provideHttpClient } from '@angular/common/http';
describe('UserService with HttpTestingController', () => {
let service: UserService;
let httpMock: HttpTestingController;
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
provideHttpClient(),
provideHttpClientTesting(),
UserService,
],
});
service = TestBed.inject(UserService);
httpMock = TestBed.inject(HttpTestingController);
});
afterEach(() => {
httpMock.verify();
});
it('should fetch users', () => {
const mockUsers: User[] = [{ id: 1, name: 'Alice', email: 'alice@example.com' }];
service.getUsers().subscribe(users => {
expect(users).toEqual(mockUsers);
});
const req = httpMock.expectOne('/api/users');
expect(req.request.method).toBe('GET');
req.flush(mockUsers);
});
});
Testing Error Handling
it('should handle errors', () => {
service.getUsers().subscribe({
error: err => {
expect(err.message).toContain('Server error');
},
});
const req = httpMock.expectOne('/api/users');
req.error(new ErrorEvent('Network error'), { status: 500, statusText: 'Server Error' });
});
Quiz
1. How do you override a provider in TestBed?
2. What does fakeAsync do?
3. How do you verify a service method was called?
Flashcards
Question
How to override providers?
Click to reveal answer
Answer
{ provide: Service, useValue: mock } in TestBed providers.
Question
What does fakeAsync do?
Click to reveal answer
Answer
Creates controlled async zone. tick() advances virtual time.
Question
How to verify method calls?
Click to reveal answer
Answer
spyOn(service, 'method') + expect(spy).toHaveBeenCalled()
Revision Notes
Key Takeaways
- 1. Override providers with useValue
- 2. fakeAsync + tick for deterministic async testing
- 3. spyOn for verifying method calls
- 4. HttpTestingController for HTTP testing
Interview Tips
- • Explain TestBed provider overriding
- • Be ready to describe fakeAsync patterns
- • Mention Jasmine spies for verification
Cheat Sheet
Service Testing Cheat Sheet
Setup:
TestBed.configureTestingModule({
providers: [
UserService,
{ provide: HttpClient, useValue: mockHttp },
],
});
fakeAsync:
it('...', fakeAsync(() => {
service.method().subscribe();
tick(1000);
expect(result).toBe(expected);
}));
Spies:
spyOn(service, 'method').and.returnValue(of(mockData));
expect(spy).toHaveBeenCalledWith(args);