如何在测试中模拟 Angular 4.3 httpClient 的错误响应 [英] How to mock Angular 4.3 httpClient an error response in testing
问题描述
我有一个下面的interceptor auth-interceptor.service.ts
import {Injectable, Injector} from '@angular/core';
import {HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from '@angular/common/http';
import {Observable} from 'rxjs/Observable';
import {Cookie} from './cookie.service';
import {Router} from '@angular/router';
import {UserService} from './user.service';
import {ToasterService} from '../toaster/toaster.service';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(private injector: Injector) {}
private handleError(err: HttpErrorResponse): Observable<any> {
let errorMsg;
if (err.error instanceof Error) {
// A client-side or network error occurred. Handle it accordingly.
errorMsg = `An error occurred: ${err.error.message}`;
} else {
// The backend returned an unsuccessful response code.
// The response body may contain clues as to what went wrong,
errorMsg = `Backend returned code ${err.status}, body was: ${err.error}`;
}
if (err.status === 401 || err.status === 403) {
this.injector.get(UserService).purgeAuth();
this.injector.get(ToasterService).showError(`Unauthorized`, errorMsg);
this.injector.get(Router).navigateByUrl(`/login`);
}
console.error(errorMsg);
return Observable.throw(errorMsg);
}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// Clone the request to add the new header.
const authReq = req.clone({headers: req.headers.set(Cookie.tokenKey, Cookie.getToken())});
// Pass on the cloned request instead of the original request.
return next.handle(authReq).catch(err => this.handleError(err));
}
}
现在我试图模拟 http.get
来抛出错误,以便方法 handleError
控制错误消息.
Now I am trying to mock the http.get
to throw the error, so that method handleError
consoles the error message.
下面是我测试用例的方法auth-interceptor.service.specs.ts
Below is my approach to the test case auth-interceptor.service.specs.ts
import {async, inject, TestBed} from '@angular/core/testing';
import {AuthInterceptor} from './auth-interceptor.service';
import {ApiService} from './api.service';
import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing';
import {environment} from '../../../environments/environment';
describe(`AuthInterceptor`, () => {
const somePath = `/somePath`;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [AuthInterceptor, ApiService]
});
});
it(`should be created`, inject([AuthInterceptor], (service: AuthInterceptor) => {
expect(service).toBeTruthy();
}));
it(`should log an error to the console on error on get()`, async(inject([ApiService, HttpTestingController],
(apiService: ApiService, httpMock: HttpTestingController) => {
spyOn(console, 'error');
apiService.get(somePath).subscribe((res) => {
console.log(`in success:`, res);
}, (error) => {
console.log(`in error:`, error);
});
const req = httpMock.expectOne(`${environment.apiUri}${somePath}`);
req.flush({
type: 'ERROR',
status: 404,
body: JSON.stringify({color: `blue`})
});
expect(console.error).toHaveBeenCalled();
}))
);
});
刷新响应时,我不确定如何刷新错误响应,以便在我的拦截器中调用方法 handleError
并最终调用 console.error
.文档没有任何关于我的情况的例子.任何帮助或建议表示赞赏.
When flushing the response, I am not sure how to flush a error response, so that the method handleError
will be called in my interceptor and that eventually calls console.error
. Documentation doesn't have any example to my situation. Any help or suggestion is appreciated.
推荐答案
HttpTestingController
类中的 expectOne
方法返回一个 TestRequest
对象.这个 TestRequest 类有一个 flush
方法,可以用来传递
The expectOne
method in HttpTestingController
class returns a TestRequest
object. This TestRequest class has a flush
method which can be used to deliver
成功和不成功的响应.
我们可以通过返回一个正文以及一些额外的响应头(如果有)来解决请求.相关信息可以在此处找到.
We can resolve the request by returning a body along with some additional response headers (if any). Relevant info can be found here.
现在,回到如何做到这一点.您可以根据您的用例自定义以下代码片段.
Now, coming back to the point how you can do this. You can customize the below code snippet as per your use case.
http = TestBed.get(HttpTestingController);
let response: any;
let errResponse: any;
const mockErrorResponse = { status: 400, statusText: 'Bad Request' };
const data = 'Invalid request parameters';
apiService.get(somePath).subscribe(res => response = res, err => errResponse = err);
http.expectOne('url/being/monitored').flush(data, mockErrorResponse);
expect(errResponse).toBe(data);
注意:在撰写此评论时,mockErrorResponse
中需要 statusText
.相关信息可以在此处找到.
NOTE: At the time of writing this comment, statusText
is required in mockErrorResponse
. Related info can be found here.
PS:TestRequest
类的 error
方法可用于在我们的测试用例中模拟网络错误,因为它需要一个错误.以下代码片段显示了这一点.
P.S.: The error
method of TestRequest
class can be used to simulate network error in our test case, as it expects an instance of Error. The following code snippet shows that.
http.expectOne(someUrl).error(new ErrorEvent('network error'));
这篇关于如何在测试中模拟 Angular 4.3 httpClient 的错误响应的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!