How to mock spyon and return an Observable in Angualr Jasmine Karma Test case

577 Views Asked by At

How to spyon an observable and mock data in this scenario. In my angular 14 app, I am writing unit tests using jasmine and karma. Following is the service(UserService) and I want to mock the observable and return mock data. It has a getUserPrefer method which call HTTP get and return ApiResp of type UserModel.

UserService.ts
export class UserService {

  constructor(private _http: HttpClient, private cService: CService) {
   }
      getUserPrefer(str: string): Observable<ApiResp<UserModel>> {
        return this._http.get<ApiResp<UserModel>>(this._cService.aConfig.customer + `v1/getuser/${str}`);
       }
}

CService.ts
export class CService {
  public get config(): IApp {
    return this._config;
  }

  public get aConfig(): IApp {
    return this._config;
  }
}

IConfig.ts
export interface IApp {
  customer: string;
}

UserService.spec.ts

import { HttpClientModule } from '@angular/common/http';
import { TestBed } from '@angular/core/testing';
import {HttpClientTestingModule, HttpTestingController} 
       from '@angular/common/http/testing';

import { UserService } from './UserService';
import { Observable} from 'rxjs';


describe('UserService', () => {
  let service: UserService;
  let userModel: UserModel;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [HttpClientModule]
    });
    service = TestBed.inject(UserService);
  });



  it('should be created', () => {
    expect(service).toBeTruthy();
  });

  it('should get UserPreference', () => {
   
   service.getUserPrefer('newuserjohn');
     spyOn(service, 'getUserPrefer')
         .and.returnValue(userModel);  
  });

});

ApiResp.ts
export interface ApiResp<T = {}> {
    status: number;
    timestamp: string;
    error?: string;
    message?: string;
    payload?: T;
}

export class UserModel {
  email!: string;
  id!: string;

  constructor(res: UserModel) {
    this.email = res.email;
  }
}
1

There are 1 best solutions below

2
wlf On

You are testing UserService so I wouldn't expect that you would be mocking functions that are implemented in that service - you should be mocking dependencies only. Hence you actually want to mock the HttpClient, to do this you should use the HttpClientTestingModule.

let httpTestingController: HttpTestingController;
...
imports: [
  ...
  HttpClientTestingModule,
  // don't import the real HttpModule
  ...
]
...
httpTestingController = TestBed.inject(HttpTestingController);

...
it('should get UserPreference', waitForAsync(() => {
   service.getUserPrefer('newuserjohn').subscribe((response_ => {
     expect(reponse).toEqual(mockUser); 
   }, fail);

   const url = 'your expected URL';
   const req = httpTestingController.expectOne(url);

   // mockUser will be returned from the mock http call, hence the check in the expect above
   req.flush(mockUser); 

   expect(req.request.method).toBe('GET');
}));

https://angular.io/api/common/http/testing/HttpTestingController