Angular 7-在单元测试中捕获HttpErrorResponse [英] Angular 7 - catching HttpErrorResponse in unit tests

查看:93
本文介绍了Angular 7-在单元测试中捕获HttpErrorResponse的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在学习Angular 7(以前没有使用任何以前的版本),并且在编写服务的单元测试时遇到无法解决的问题.

i'm currently learning Angular 7 (haven't used any previous version) and encountered something i couldn't fix when writing unit tests for a service.

我有一个从REST获取JSON并将其解析为Class的服务. 提到Angular Docs,我使用HttpClientSpy编写了一个模拟404错误的测试.

I have a service that gets JSON from REST and parses it into a Class. Referring to the Angular Docs, i wrote a test using HttpClientSpy to simulate a 404 Error.

发生了什么:测试失败并显示以下错误消息:预期数据.forEach不是包含'404'的函数"

What happens: The Test Fails with the Error Message: "expected data.forEach is not a function to contain '404'"

因此,该服务将HttpErrorResponse作为输入,但尝试解析它,就像它是map函数中的常规响应一样.失败,调用catchError,并且data.forEach不是函数抛出错误.

So the Service gets the HttpErrorResponse as Input but tries to parse it like it was a regular response in the map function. This fails, catchError is called and the data.forEach is not a function Error is thrown.

预期的行为:我希望没有执行map(),它应该直接跳到catchError函数中.

Expected behavior: i would expect that map() is not executed and it should jump directly into the catchError function.

我如何修复(目前):将以下代码行添加到服务的地图功能使测试正常进行.

How i fixed it (for now): Adding the following lines of code to the map function of the service makes the test work.

if (data instanceof HttpErrorResponse)
      throw new HttpErrorResponse(data);

测试:

it('should throw an error when 404', () => {

const errorResponse = new HttpErrorResponse({
  error: '404 error',
  status: 404, statusText: 'Not Found'
});

httpClientSpy.get.and.returnValue(of(errorResponse));

service.getComments().subscribe(
  fail,
  error => expect(error.message).toContain('404')
);
});

服务:

getComments(): Observable<CommentList> {
return this.http
.get('https://jsonplaceholder.typicode.com/comments')
.pipe(
  map((data: Array<any>) => {
    let t: Array<Comment> = [];

    data.forEach(comment => {

      if(!('id' in comment) || !('body' in comment) || !('email' in comment) || !('name' in comment))
        throw new Error("Could not cast Object returned from REST into comment");

      t.push(<Comment>{
        id: comment.id,
        body: comment.body,
        author: comment.email,
        title: comment.name,
      });

    });
    return new CommentList(t);
  }),
  catchError((err: HttpErrorResponse) => {
    return throwError(err);
  })
);
}

我弄错了吗?我认为预期的行为是我应该经历的,至少这就是我解释Angular文档的方式.

Am i getting something wrong? I think the expected behavior is what i should experience, at least thats how i interpret the Angular docs.

推荐答案

最新答案,但可能会帮助面临类似问题的人.

Late answer, but may help someone facing similar issue.

错误消息:预期数据.forEach不是包含'404'的函数"是由于测试用例中的of运算符:

The Error Message: "expected data.forEach is not a function to contain '404'" is because of the of operator in the test case:

httpClientSpy.get.and.returnValue(of(errorResponse));

of运算符返回一个可观察变量,该变量发出参数.

The of operator returns an observable that emits the arguments.

这在您要返回数据时有用,而在您要引发404错误时则无济于事.

This is useful when you want to return data, but not when you want to raise a 404 error.

为了使间谍引发错误,响应应该拒绝而不是解决.

In order for the spy to raise error, the response should reject and not resolve.

此解决方案使用defer RxJS运算符以及您在示例中使用的jasmine.createSpyObj方法.

This solution uses the defer RxJS operator along with jasmine.createSpyObj approach you used in your example.

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

import { CommentsService } from './comments.service';

// Create async observable error that errors
//  after a JS engine turn
export function asyncError<T>(errorObject: any) {
  return defer(() => Promise.reject(errorObject));
}

describe('CommentsService', () => {
  let httpClientSpy: { get: jasmine.Spy };
  let service: CommentsService;

  beforeEach(() => {
    httpClientSpy = jasmine.createSpyObj('HttpClient', ['get']);
    service = new CommentsService(httpClientSpy as any);
  });

  it('should throw an error when 404', () => {
    const errorResponse = new HttpErrorResponse({
      error: '404 error',
      status: 404,
      statusText: 'Not Found'
    });

    httpClientSpy.get.and.returnValue(asyncError(errorResponse));

    service.getComments().subscribe(
      data => fail('Should have failed with 404 error'),
      (error: HttpErrorResponse) => {
        expect(error.status).toEqual(404);
        expect(error.error).toContain('404 error');
      });
  });
});

解决方案2

最好使用有角 HttpClientTestingModule 来测试HttpClient用法.以下示例显示了使用HttpClientTestingModule的相同测试.

Solution 2

It is better to use the angular HttpClientTestingModule to test the HttpClient usage. The following example shows the same test using HttpClientTestingModule.

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

import { CommentsService } from './comments.service';

describe('CommentsService test using HttpClientTestingModule', () => {
  let httpTestingController: HttpTestingController;
  let service: CommentsService;

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

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

  it('throws 404 error', () => {
    service.getComments().subscribe(
      data => fail('Should have failed with 404 error'),
      (error: HttpErrorResponse) => {
        expect(error.status).toEqual(404);
        expect(error.error).toContain('404 error');
      }
    );

    const req = httpTestingController.expectOne('https://jsonplaceholder.typicode.com/comments');

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

有角度的 HTTP测试文档说明了这种方法.

The angular HTTP Testing documentation explains this approach.

注意:这些示例已使用Angular v8进行了测试.

Note: The examples are tested using Angular v8.

这篇关于Angular 7-在单元测试中捕获HttpErrorResponse的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆