Back to course

Testing Services and Dependency Injection Mocks

The Complete Angular Developer: From Zero to Hero

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.