Mock Service Using SpyOn | Angular Unit Testing | Karma | Jasmine


How to use spyOn in Angular Unit Testing? How to mock a service in Angular Unit Testing ?

{% include youtube_embed.html id=“l4oYN3TvKM4” %}

Here is your component code that you want to unit test.

import { Component } from '@angular/core';
import { DataServiceService } from '../app/data-service.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'angu-unit-test';

  constructor(private dataService : DataServiceService){}

  count = 0;
  config = {};
  data;

  calculate(a,b){
    this.count = (a * b) + 100
    return this.count;
  }

  saveConfigLocally(param){
    this.config = param;
  }

  saveData(){
    let req_params = {
      count : this.calculate(10,10),
      name : "sam"
    };
    this.saveConfigLocally(req_params);
    this.dataService.saveConfigData(req_params).subscribe(response => {
      this.data = response;
    })
  }
}

Let’s write unit test case for saveData method. Analyzing the method you can see that it’s making three external calls, calculate, saveConfigLocally and a service call saveConfigData.

Now while unit testing saveData the aim is to unit test the method and not the external calls it makes. So, you need to mock the method and API service method calls.

You can use spyOn to mock the methods.

spyOn provides a couple of options to return the response to the intercepted method calls. You can return a value using returnValue method, suppress the method call using stub or return an observable using callFake.

Here is the unit test case for saveData

import { TestBed, async } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { AppComponent } from './app.component';
import { DataServiceService } from './data-service.service';
import { of } from 'rxjs';

describe('AppComponent', () => {
  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [
        RouterTestingModule,
        HttpClientTestingModule
      ],
      declarations: [
        AppComponent
      ],
    }).compileComponents();
  }));

  it('should call saveData', () => {
  
    const fixture = TestBed.createComponent(AppComponent);
    const app = fixture.componentInstance;
    spyOn(app, "calculate").and.returnValue(1000);
    spyOn(app,"saveConfigLocally").and.stub();
    let service = fixture.debugElement.injector.get(DataServiceService);
    spyOn(service,"saveConfigData").and.callFake(() => {
      return of({
        "statusCode" : 200
      });
    })
    app.saveData();
    expect(app.data).toEqual({
      "statusCode" : 200
    });

  })
});

As seen in the above code, you have mocked the method call calculate using spyOn and returning a value. You have spied on the method saveConfigLocally and stubbed it. You mocked the service call using spyOn and callFake to return an observable.