75. Testing Services and Dependency Injection Mocks
Services contain business logic and data fetching, making them prime candidates for unit testing. When testing a service that relies on another service (a dependency), we use mocks/spies to isolate the unit being tested.
1. Testing a Service with No Dependencies
We instantiate the service directly.
typescript describe('MathService', () => { let service: MathService;
beforeEach(() => { service = new MathService(); });
it('should calculate the sum correctly', () => { expect(service.add(2, 3)).toBe(5); }); });
2. Testing a Service with Dependencies (Mocking)
We often need to mock dependencies like HttpClient or AuthService. Instead of making real API calls, we replace the dependency with a spy object that controls the return value.
typescript describe('UserService', () => { let userService: UserService; let mockHttp: any; // The spy/mock for HttpClient
beforeEach(() => { // Create a mock with the methods we expect to be called mockHttp = jasmine.createSpyObj('HttpClient', ['get']);
TestBed.configureTestingModule({
providers: [
UserService,
// Provide the mock instead of the real HttpClient
{ provide: HttpClient, useValue: mockHttp }
]
});
userService = TestBed.inject(UserService);
});
it('should call GET when fetching users', () => { // Define what the mock's 'get' method should return (an Observable) mockHttp.get.and.returnValue(of([{ id: 1, name: 'Test' }]));
userService.getUsers().subscribe(users => {
expect(users.length).toBe(1);
});
// Verify the mock was called correctly
expect(mockHttp.get).toHaveBeenCalledWith('/api/users');
}); });
Using TestBed.inject() retrieves the service instance that lives within the testing module.