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
.