Mocking HTTP responses with HttpClientTestingController 

It is super simple to get started with mocking HTTP, once you understand how to. Let's first have a look at the service we mean to test:

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';

@Injectable()
export class JediService {
apiUrl: string = 'something';
constructor(private http: HttpClient) {}

getJedis() {
return this.http.get(`/api/jedis`);
}
}

There are two important players when it comes to testing our service:

  • HttpTestingController, we can instruct this class to listen for specific URLs and how to respond when it is being called
  • Our service, this is the service we want to test; the only thing we really want to do with it is to invoke it

As with all tests, we have a setup phase. Here we need to import the module, HttpClientTestingModule, that contains our HttpTestingController. We also need to tell it to provide us with our service, like so:

import { 
HttpClientTestingModule,
HttpTestingController

} from '@angular/common/http/testing';
import { JediService } from './jedi.service';

describe('testing our service', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [JediService]
});
});
});

The next step is to set up the test, and by set up we mean that we need to get an instance of our service as well as HttpTestingController. We also need to instruct the latter what type of API calls to expect and give it suitable mock data to respond with:

it('testing getJedis() and expect a list of jedis back', () => {
// get an instance of a Jedi service and HttpTestingController
const jediService = TestBed.get(JediService);
const http = TestBed.get(HttpTestingController);

// define our mock data
const expected = [{ name: 'Luke' }, { name: 'Darth Vader' }];
let actual = [];

// we actively call getJedis() on jediService,
// we will set that response to our 'actual' variable
jediService.getJedis().subscribe( data => {
expect(data).toEqual(expected);
});

/*
when someone calls URL /api/jedis
we will resolve that asynchronous operation
with .flush() while also answering with
'expected' variable as response data
*/
http.expectOne('/api/jedis').flush(expected);
});

We have provided inline comments for the preceding code snippet, but just to describe what happens one more time ,we have three phases to our test:

  1. Arrange: This is where we grab an instance of the JediService as well as an instance of the HttpTestingController. We also define our mock data by setting the expected  variable.
  2. Act: We carry out the test by calling jediService.getJedis(). This is an observable so we need to subscribe to its content.
  3. Assert: We resolve the asynchronous code by calling flush(expected) and we assert that we get the right data back by carrying out our assertion expect(actual).toEqual(expected).

As you can see, faking calls to the HTTP is quite easy. Let's show the entire unit test code:

import { 
HttpTestingController,
HttpClientTestingModule

}
from '@angular/common/http/testing/';
import { TestBed } from '@angular/core/testing';

import { JediService } from './jedi-service';

describe('a jedi service', () => {
beforeEach(() => TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [JediService]
}));

it('should list the jedis', () => {
const jediService = TestBed.get(JediService);
const http = TestBed.get(HttpTestingController);

// fake response
const expected = [{ name: 'Luke' }, { name: 'Darth Vader' }];
let actual = [];

jediService.getJedis().subscribe( data => {
expect(data).toEqual(expected);
});

http.expectOne('/api/jedis').flush(expected);
});
});
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset