How to test a service in your Angular app with TestBed
According to what you want to test when testing a service, there are two approaches. The first one is used to test if the component behaves as expected after interacting with a service. The second one verifies that the interaction with the service is executed as expected.
Testing services
To test a service you will need TestBed, a testing utility to provide and create services. I tried two ways to test a service:
- mocking the service,
- mocking the response.
How to mock a service
To test a service, I created a mocked service that simulates a response, and I set it in the providers:
let service: ValueService;
beforeEach(() => {
TestBed.configureTestingModule({ providers: [ValueService] });
service = TestBed.inject(ValueService);
});
test example:
beforeEach(async(() => {
testObject = {
name: "test"
};
testResponse = {
has_more: false,
items: [testObject],
};
};
TestBed.configureTestingModule({
imports: [
TestComponentModule,
HttpClientTestingModule,
],
providers: [
{
provide: TestService,
useValue: {
testObjectGet: () => of(testResponse),
},
},
],
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(TestComponent);
component = fixture.componentInstance;
fixture.detectChanges();
httpTestingController = TestBed.inject(HttpTestingController);
});
it('a test using a mocked service', () => {
expect(
fixture.debugElement.query(By.css('h5')).nativeElement.textContent,
).toContain(testResponse.items?.[0].name);
});
In this case I'm testing the behavior of the component working as expected with a service, I'm not testing the service interaction. The component is tested in a more isolated condition.
How to mock a response
When mocking the response, I want to test if the service is called in the expected way. Doing so I can test if the method is correct, the parameters, the format response, and so on.
beforeEach(() => {
fixture = TestBed.createComponent(ChannelRecordersListPageComponent);
component = fixture.componentInstance;
testObject = {
name: "test"
};
testResponse = {
has_more: false,
items: [testObject]
};
fixture.detectChanges();
httpTestingController = TestBed.inject(HttpTestingController);
});
it("test that the test response is correctly get by the service", async(() => {
const testUrl = "http://my-test-url";
const testRequest = httpTestingController.expectOne(testUrl);
expect(testRequest.request.method).toEqual("GET");
testRequest.flush(testResponse);
httpTestingController.verify();
}));
Conclusions
What I need is usually the first approach, more decoupled and independent of the service.