How to unit test an Angular service?

Yesterday, we covered how to unit test an Angular pipe. Services are a bit more complex to test because they usually have dependencies that need to be injected. Let’s consider this example:

All the service does is rely on the HttpClient to make requests to a server. In a unit test, we don’t want to have a server up and running for the test to work. Instead, we want to focus on CartService only and replace all its dependencies with fake implementations called mocks.

Replacing a dependency with a mock requires some dependency injection config, which is why the setup of a service test is different. Here is what Angular CLI generates for us automatically:

We can see that the test relies on a TestBed object to create a testing module and then inject CartService in our test. TestBed is an Angular utility that enables custom dependency injection in unit tests. We are going to use TestBed to replace our real HttpClient with a fake one.

The simplest fake implementation we can create to satisfy our unit test is the following:

The above mock object has hardcoded methods that return the same Observables for each HTTP request. The next step is to configure our TestBed so our test uses that mock instead of the real HttpClient:

At this point, our test setup is ready. We can start writing actual test cases. We want to test getCartContents and make sure that it returns an empty array. The challenge at that point is that our method returns an Observable, which means we have to subscribe to it and then test the result:

The above test works! We got the Observable from our mock and checked the empty array. The test passes. That said, when working with Observables, it is recommended to use the async function as follows to make sure that the test waits long enough before completing:

Note that async has to be passed as a parameter to the test function (first line of code) and then called as the last line in our subscribe callback function.

There are other approaches to testing services that rely on the HttpClient. This one is the most straightforward, but if you’re interested, I have another tutorial that uses the official Angular mock API for the HttpClient.

Alain Chautard

Alain is a Google Developer Expert in Web Technologies, Angular, and Google Maps. His daily mission is to help development teams adopt Angular and build at scale with the framework. He has taught Angular on all six continents! A world traveler and photographer, Alain is also an international conference speaker, and a published author of several video courses.