Angular
  • Angular learning
  • Angular
    • Change Detection
      • Angular Change Detection Strategies
      • Understanding Change Detection Strategy in Angular
    • Angular Components Overview
      • Lifecycle hooks
      • View encapsulation
    • Text interpolation
    • Pipes
    • ARIA
    • Event binding
    • Directives
    • Dependency injection in Angular
    • Difference between Template-Driven and Reactive Forms
    • Guards
    • Resolvers
      • Resolver example
  • Memory management in Angular applications
  • Renderer2
  • Angular test
    • Testing
      • The different types of tests
      • Some testing best practices
      • Angular Service Testing in Depth
        • About Jasmine
        • Jasmine - Test suites
        • Implementation of First Jasmine Specfication
        • spyOn() & jasmine.createSpyObj()
        • beforeEach()
        • Testing services
        • Disabled and Focused Tests
        • flush
        • HttpTestingController
        • Sample code
      • Angular Component Testing in Depth
        • Intro to Angular Component testing
        • DOM interaction
        • Trigger Change Detection
        • Test Card List Test Suite Conclusion
        • Window.requestAnimationFrame()
        • Asynchronous Work (Jasmine)
        • Cooperative asynchronous JavaScript: Timeouts and intervals
        • FakeAsync - Asynchronous Work (Jasmine) part 2
        • tick()
        • Sample codes
      • Testing Promised-based code-intro Microtasks
        • Microtasks
        • Micro-tasks within an event loop (Summary)
        • Macro-tasks within an event loop (Summary)
        • Test promised Microtasks (code)
      • Using fakeAsync to test Async Observables
      • Cypress.io
        • Create our first e2e test
      • Angular CLI code coverage and deployment in prod mode.
      • Travis CI
  • Angular best practices
    • Angular best practices
      • Security
      • Accessibility in Angular
      • Keeping your Angular projects up-to-date
    • Bootstrapping an Angular Application
      • Understanding the File Structure
      • Bootstrapping Providers
    • Components in Angular
      • Creating Components
      • Application Structure with Components
        • Accessing Child Components from Template
        • Using Two-Way Data Binding
        • Responding to Component Events
        • Passing Data into a Component
      • Projection
      • Structuring Applications with Components
      • Using Other Components
  • Reactive extensions
    • RxJS
      • RxJS Operators
      • of
      • Observable
      • async pipe (Angular)
      • Interval
      • fromEvent
      • Pipe
      • Map
      • Tap
      • ShareReplay
      • Concat
      • ConcatMap
      • Merge
      • MergeMap
      • ExhaustMap
      • fromEvent
      • DebounceTime
        • Type Ahead
      • Distinct Until Changed
      • SwitchMap
      • CatchError
      • Finalize
      • RetryWhen
      • DelayWhen
      • ForkJoin
      • First
      • Interview Questions
      • Zip
  • NgRx
    • What's NgRx
      • Actions
      • Reducers
      • Selectors
      • 🙅‍♂️Authentication guard with NgRX
      • @ngrx/effects
        • Side-Effect refresh survivor
  • Interview Q&A
    • Angular Unit Testing Interview Questions
    • Angular Questions And Answers
  • Angular Advanced
    • Setting up our environment
      • Understanding Accessors (TS)
      • The host & ::ng-deep Pseudo Selector
Powered by GitBook
On this page
  • Service + Component
  • Testing Setup

Was this helpful?

  1. Angular test
  2. Testing
  3. Angular Service Testing in Depth

HttpTestingController

Controller to be injected into tests, that allows for mocking and flushing of requests.

PreviousflushNextSample code

Last updated 4 years ago

Was this helpful?

Angular’s new HttpClient has a testing module, , that makes it easy to unit test HTTP requests. In this short post we’ll go over how to setup a simple unit test for an http GET request using that module, and in turn it should help demonstrate the capabilities of that new testing module.

Since HttpClient is available only starting with Angular 4.3, the following applies to Angular 4.3+. Have a look at if you’re new to unit testing in Angular.

Service + Component

For this post we’ll be working with a simple service that gets data from an endpoint and a component that calls that service to populate a list of users in the component’s OnInit hook.

Here’s our service:data.service.ts

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

@Injectable()
export class DataService {
  url = 'https://jsonplaceholder.typicode.com/users';
  constructor(private http: HttpClient) {}
  getData() {
    const req = new HttpRequest('GET', this.url, {
      reportProgress: true
    });
return this.http.request(req);

And our component looks like the following:app.component.ts

import { Component, OnInit } from '@angular/core';
import { HttpEvent, HttpEventType } from '@angular/common/http';

import { DataService } from './data.service';
@Component({ ... })
export class AppComponent implements OnInit {
  users: any;
  constructor(private dataService: DataService) {}
  ngOnInit() {
    this.populateUsers();
  }

Testing Setup

Now we’ll setup a spec file for our data service and include the necessary utilities to test out the HttpClient requests. On top of HttpClientTestingModule, we’ll also need HttpTestingController, which makes it easy to mock requests:data.service.spec.ts

import { TestBed, inject } from '@angular/core/testing';
import { HttpEvent, HttpEventType } from '@angular/common/http';

import {
  HttpClientTestingModule,
  HttpTestingController
} from '@angular/common/http/testing';
import { DataService } from './data.service';
describe('DataService', () => {
  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule],
      providers: [DataService]
    });
  });

We use the inject utility to inject the needed services into our test.

With this in place, we can add our test logic:data.service.spec.ts (partial)

const mockUsers = [
  { name: 'Bob', website: 'www.yessss.com' },
  { name: 'Juliette', website: 'nope.com' }
];

dataService.getData().subscribe((event: HttpEvent<any>) => {
  switch (event.type) {
    case HttpEventType.Response:
      expect(event.body).toEqual(mockUsers);
  }
});
const mockReq = httpMock.expectOne(dataService.url);
expect(mockReq.cancelled).toBeFalsy();
expect(mockReq.request.responseType).toEqual('json');
mockReq.flush(mockUsers);

There’s quite a bit going on, so let’s break it down:

  • First we define a couple of mock users that we’ll test against.

  • We then call the getData method in the service that we’re testing and subscribe to returned observable.

  • If the HttpEventType is of type Response, we assert for the response event to have a body equal to our mock users.

  • We then make use of the HttpTestingController (injected in the test as httpMock) to assert that one request was made to the service’s url property. If no request is expected, the expectNone method can also be used.

  • We can now make any number of assertions on the mock request. Here we assert that the request hasn’t been cancelled and the the response if of type json. Additionally, we could assert the request’s method (GET, POST, …)

  • Next we call flush on the mock request and pass-in our mock users. The flush method completes the request using the data passed to it.

  • Finally, we call the verify method on our HttpTestingController instance to ensure that there are no outstanding requests to be made.

Here’s our complete test setup:data.service.spec.ts

import { TestBed, inject } from '@angular/core/testing';
import { HttpEvent, HttpEventType } from '@angular/common/http';

import {
  HttpClientTestingModule,
  HttpTestingController
} from '@angular/common/http/testing';
import { DataService } from './data.service';
describe('DataService', () => {
  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule],
      providers: [DataService]
    });
  });
  it(
    'should get users',
    inject(
      [HttpTestingController, DataService],
      (httpMock: HttpTestingController, dataService: DataService) => {
        const mockUsers = [
          { name: 'Bob', website: 'www.yessss.com' },
          { name: 'Juliette', website: 'nope.com' }
        ];
    dataService.getData().subscribe((event: HttpEvent&lt;any&gt;) => {
      switch (event.type) {
        case HttpEventType.Response:
          expect(event.body).toEqual(mockUsers);
      }
    });

    const mockReq = httpMock.expectOne(dataService.url);

    expect(mockReq.cancelled).toBeFalsy();
    expect(mockReq.request.responseType).toEqual('json');
    mockReq.flush(mockUsers);

    httpMock.verify();
  }
)

It may seem like a lot of boilerplate at first, but with this in place you’ll be ready to test out all kinds of http request scenarios.

HttpClientTestingModule
this introduction