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.