我目前正在学习Angular 7(以前没有使用任何以前的版本),并且在编写服务的单元测试时遇到了无法解决的问题。
我有一个从REST获取JSON并将其解析为Class的服务。 提到Angular Docs,我使用HttpClientSpy编写了一个模拟404错误的测试。
会发生什么情况:测试失败并显示错误消息:“预期数据。forEach不是包含'404'的函数”
因此,该服务将HttpErrorResponse作为输入,但是尝试解析它,就像它是map函数中的常规响应一样。失败,将调用catchError,并且data.forEach不是函数会引发错误。
预期的行为:我希望不会执行map(),它应该直接跳到catchError函数中。
我如何修复(目前):将以下代码行添加到服务的地图功能使测试正常进行。
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文档的方式。
答案 0 :(得分:1)
一个较晚的答案,稍有不同,但这也可以。
it('should show modal if failed', inject([Router], (mockRouter: Router) => {
const errorResponse = new HttpErrorResponse({
error: { code: `some code`, message: `some message.` },
status: 400,
statusText: 'Bad Request',
});
spyOn(someService, 'methodFromService').and.returnValue(throwError(errorResponse));
expect...
expect...
expect...
}));
答案 1 :(得分:0)
最新答案,但可能会帮助面临类似问题的人。
错误消息:“预期的data.forEach不是包含'404'的函数”是由于在测试用例中使用了of
运算符:
httpClientSpy.get.and.returnValue(of(errorResponse));
of
运算符返回一个可观察变量,该变量发出参数。
这在您要返回数据时有用,而在您要引发404错误时则无用。
为了使间谍举报错误,响应应该拒绝而不是解决。
此解决方案使用defer
RxJS运算符以及您在示例中使用的jasmine.createSpyObj
方法。
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');
});
});
});
最好使用成角的HttpClientTestingModule来测试HttpClient
的用法。以下示例显示了使用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 Testing文档说明了这种方法。
注意:这些示例已使用Angular v8进行了测试。