Jasmine: Unit test http service error observable

柔情痞子 提交于 2019-12-07 08:45:56

问题


I am pretty confused on how to mock that my http service catches an observable error. I have read through the angular documentation but I do not understand how I would structure the test. I would like to mock an error in my service, then check that it catches an error observable. I have another service that creates and throws the error observable. The rest of my services just catch it when encountering an error. I am honestly very confused on how to implement this. Here is a simple verison of my service, and also the error service:

getData(url: string): Observable<any> {
    return this.http.get(url)
       .map(this.extractData)
        .catch(this.handleErrorObservable);
}

  handleErrorObservable(error: Response | any) {
    console.error(error.message || error);
    return Observable.throw(error.message || error);
}

Now how would I simulate an error? Do I need to spy on the service and make it fail? Would something along the lines of spyOn(service, 'getData).and.returnValue(Observable.throw({status: 404}))) or am I looking at this the wrong way? Thanks.

EDIT: Code with Castro Roy's solution.

import {HttpErrorResponse, } from '@angular/common/http';
import { TestBed, inject } from '@angular/core/testing'
import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing'
import {HttpService} from '../services/http.service'

fdescribe('MyService', () => {
    let httpTestingController: HttpTestingController;

    beforeEach(() => {
        TestBed.configureTestingModule({
            imports: [HttpClientTestingModule],
            providers: [HttpService]
        });
        httpTestingController = TestBed.get(HttpTestingController);
    });

    afterEach(() => {

        httpTestingController.verify();
    });

    it('should be created', inject([HttpService], (service: HttpService)=> {
        expect(service).toBeTruthy();
    }));

    it('should handleErrorObservable', inject([HttpService], (service: HttpService) => {
        const urlString = '/data';
        const emsg = 'deliberate 404 error';

        spyOn(service, 'handleErrorObservable').and.callThrough();

        service.getData(urlString).subscribe(
            data => fail('should have failed with the 404 error'),
            (error: HttpErrorResponse) => {

              expect(service.handleErrorObservable).toHaveBeenCalled(); // check if executed

              expect(error.status).toEqual(404, 'status');
              expect(error.error).toEqual(emsg, 'message');

             });

        const req = httpTestingController.expectOne(urlString);


        req.flush(emsg, { status: 404, statusText: 'Not Found' });
      }));
});

回答1:


spyOn(service, 'getData').and.returnValue(Observable.throw({status: 404}))) migth be useful if you are trying to mock getData to some other service that use it, but handleErrorObservable will never be executed. So, if you want to test that handleErrorObservable have been called, something like this should help you:

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

import { MyService } from './MyService';

describe('MyService', () => {
  let httpTestingController: HttpTestingController;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule],
      providers: [MyService]
    });

    httpTestingController = TestBed.get(HttpTestingController);
  });

  afterEach(() => {
    // After every test, assert that there are no more pending requests.
    httpTestingController.verify();
  });

  it('should be created', inject([MyService], (service: MyService) => {
    expect(service).toBeTruthy();
  }));

  it('should handleErrorObservable', inject([MyService], (service: MyService) => {
    const urlString = '/data';
    const emsg = 'deliberate 404 error';

    spyOn(service, 'handleErrorObservable').and.callThrough();

    service.getData(urlString).subscribe(
        data => fail('should have failed with the 404 error'),
        (error: HttpErrorResponse) => {

          expect(service.handleErrorObservable).toHaveBeenCalled(); // check if executed

          expect(error.status).toEqual(404, 'status');
          expect(error.error).toEqual(emsg, 'message');
        }
    });

    const req = httpTestingController.expectOne(urlString);

    // Respond with mock error
    req.flush(emsg, { status: 404, statusText: 'Not Found' });
  }));
});

Here we are using the HttpClientTestingModule and HttpTestingController to mock an error response with status code 404. Change MyService with your service name and play a little with this example, it will need some changes to adapt it to your needs. More info in the docs

Also, take a look to another question where are using a different way of mocking the HttpClient service.

Hope it helps.



来源:https://stackoverflow.com/questions/51156450/jasmine-unit-test-http-service-error-observable

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!