如何使用 Jasmine 在 Angular 中对 HTTP 拦截器进行单元测试
How to unit test an HTTP interceptor in Angular using Jasmine
我的 angular 应用程序中有以下 http 拦截器,我想使用 Jasmine 对其进行单元测试。我用谷歌搜索了其中一些并尝试了但它没有按预期工作。请找到下面的 HttpInterceptorService.ts 文件代码
export class HttpInterceptorService Implements HttpInterceptor {
counter = 0;
constructor(private loaderService: LoaderService) { }
intercept(req: HttpRequest<any>, next: HttpHandler) {
if (req.url !== '/getUsers') {
this.counter ++;
}
this.loaderService.setStatus(true);
return next.handle(req).pipe(
finalize(() => {
if (req.url !== 'getUsers') {
this.counter --;
}
if (this.counter === 0) {
this.loaderService.setStatus(false);
}
};
);
}
}
下面是我目前尝试的 HttpInterceptor.service.spec.ts 文件代码。我不确定如何测试其中的特定方法。
describe('HttpInterceptorService', () => {
let httpService: HttpService;
let httpMock: HttpTestingController;
let interceptor: HttpInterceptorService;
beforeEach(()=> {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [
HttpService,
{provide:HTTP_INTERCEPTOR, useClass: HttpInterceptorService, multi: true},
]
});
httpService = TestBed.get(HttpService);
httpMock = TestBed.get(HttpTestingController);
interceptor = TestBed.get(HttpInterceptorService);
});
it('should increment the counter for all api's expect getUsers', ()=> {
httpService.get('getAdminList').subscribe(res => {
expect(res).toBeTruthy();
expect(interceptor.counter).toBeGreaterThan(0);
});
});
});
在检查参考代码后,我可以用上述更改覆盖几行代码。但我仍然无法涵盖 finalize 方法。请求帮助。
从提供商中删除 HttpInterceptorService
,因为您已经在下一行 { provide:HTTP_INTERCEPTOR, ...
中提供了它。尝试遵循本指南:https://alligator.io/angular/testing-http-interceptors/. It seems like you need to have a service that actually makes API calls. Try to follow this guide as well: https://www.mobiquity.com/insights/testing-angular-http-communication
我认为要进行 HTTP 调用,您只需 httpClient.get('www.google.com').subscribe()
即可,您不需要像第一个指南所示的实际服务 (DataService
)。
编辑:
describe('HttpInterceptorService', () => {
let httpService: HttpService;
let httpMock: HttpTestingController;
let interceptor: HttpInterceptorService;
// mock your loaderService to ensure no issues
let mockLoaderService = { setStatus: () => void };
beforeEach(()=> {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [
HttpService,
{provide:HTTP_INTERCEPTOR, useClass: HttpInterceptorService, multi: true},
// provide the mock when the unit test requires
// LoaderService
{ provide: LoaderService, useValue: mockLoaderService },
]
});
httpService = TestBed.get(HttpService);
httpMock = TestBed.get(HttpTestingController);
interceptor = TestBed.get(HttpInterceptorService);
});
it('should increment the counter for all api's except getUsers', ()=> {
httpService.get('getAdminList').subscribe(res => {
expect(res).toBeTruthy();
expect(interceptor.counter).toBeGreaterThan(0);
});
});
// add this unit test
it('should decrement the counter for getUsers', ()=> {
httpService.get('getUsers').subscribe(res => {
expect(res).toBeTruthy();
expect(interceptor.counter).toBe(0);
});
});
});
活生生的例子@
describe('AuthHttpInterceptor', () => {
let http: HttpClient,
httpTestingController: HttpTestingController,
mockAuthService: AuthorizationService;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule, SharedModule],
providers: [
{
provide: AuthorizationService,
useClass: MockAuthorizationService
},
{
provide: HTTP_INTERCEPTORS,
useClass: AuthorizationInterceptor,
multi: true
},
// One of these tests trigger a console.error call and is expected
// Mocking the logger prevents this otherwise another test run outside this suite
// to prevent console.error calls will fail.
{
provide: LoggerInjectionToken,
useValue: mockLogger
}]
});
http = TestBed.inject(HttpClient);
httpTestingController = TestBed.inject(HttpTestingController);
mockAuthService = TestBed.inject(AuthorizationService);
});
示例测试:
it('will refresh token and re-issue request should 401 be returned.', (() => {
spyOn(mockAuthService, 'requestNewToken').and.callFake(() => {
return of({
renewed: true,
accessToken: 'token'
});
});
http.get('/data')
.subscribe((data) => {
expect(data).toEqual('Payload');
});
const failedRequest = httpTestingController.match('/data')[0];
failedRequest.error(new ErrorEvent('Er'), { status: 401 });
const successReq = httpTestingController.match('/data')[0];
successReq.flush('Payload', { status: 200, statusText: 'OK' });
expect(mockAuthService.requestNewToken).toHaveBeenCalled();
httpTestingController.verify();
}));
直接看需求
下面的代码有助于覆盖 finalize 运算符中的代码。
const next: any = {
handle: () => {
return Observable.create(subscriber => {
subscriber.complete();
});
}
};
const requestMock = new HttpRequest('GET', '/test');
interceptor.intercept(requestMock, next).subscribe(() => {
expect(interceptor.counter).toBeGreaterThan(0);
});
我的 angular 应用程序中有以下 http 拦截器,我想使用 Jasmine 对其进行单元测试。我用谷歌搜索了其中一些并尝试了但它没有按预期工作。请找到下面的 HttpInterceptorService.ts 文件代码
export class HttpInterceptorService Implements HttpInterceptor {
counter = 0;
constructor(private loaderService: LoaderService) { }
intercept(req: HttpRequest<any>, next: HttpHandler) {
if (req.url !== '/getUsers') {
this.counter ++;
}
this.loaderService.setStatus(true);
return next.handle(req).pipe(
finalize(() => {
if (req.url !== 'getUsers') {
this.counter --;
}
if (this.counter === 0) {
this.loaderService.setStatus(false);
}
};
);
}
}
下面是我目前尝试的 HttpInterceptor.service.spec.ts 文件代码。我不确定如何测试其中的特定方法。
describe('HttpInterceptorService', () => {
let httpService: HttpService;
let httpMock: HttpTestingController;
let interceptor: HttpInterceptorService;
beforeEach(()=> {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [
HttpService,
{provide:HTTP_INTERCEPTOR, useClass: HttpInterceptorService, multi: true},
]
});
httpService = TestBed.get(HttpService);
httpMock = TestBed.get(HttpTestingController);
interceptor = TestBed.get(HttpInterceptorService);
});
it('should increment the counter for all api's expect getUsers', ()=> {
httpService.get('getAdminList').subscribe(res => {
expect(res).toBeTruthy();
expect(interceptor.counter).toBeGreaterThan(0);
});
});
});
在检查参考代码后,我可以用上述更改覆盖几行代码。但我仍然无法涵盖 finalize 方法。请求帮助。
从提供商中删除 HttpInterceptorService
,因为您已经在下一行 { provide:HTTP_INTERCEPTOR, ...
中提供了它。尝试遵循本指南:https://alligator.io/angular/testing-http-interceptors/. It seems like you need to have a service that actually makes API calls. Try to follow this guide as well: https://www.mobiquity.com/insights/testing-angular-http-communication
我认为要进行 HTTP 调用,您只需 httpClient.get('www.google.com').subscribe()
即可,您不需要像第一个指南所示的实际服务 (DataService
)。
编辑:
describe('HttpInterceptorService', () => {
let httpService: HttpService;
let httpMock: HttpTestingController;
let interceptor: HttpInterceptorService;
// mock your loaderService to ensure no issues
let mockLoaderService = { setStatus: () => void };
beforeEach(()=> {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [
HttpService,
{provide:HTTP_INTERCEPTOR, useClass: HttpInterceptorService, multi: true},
// provide the mock when the unit test requires
// LoaderService
{ provide: LoaderService, useValue: mockLoaderService },
]
});
httpService = TestBed.get(HttpService);
httpMock = TestBed.get(HttpTestingController);
interceptor = TestBed.get(HttpInterceptorService);
});
it('should increment the counter for all api's except getUsers', ()=> {
httpService.get('getAdminList').subscribe(res => {
expect(res).toBeTruthy();
expect(interceptor.counter).toBeGreaterThan(0);
});
});
// add this unit test
it('should decrement the counter for getUsers', ()=> {
httpService.get('getUsers').subscribe(res => {
expect(res).toBeTruthy();
expect(interceptor.counter).toBe(0);
});
});
});
活生生的例子@
describe('AuthHttpInterceptor', () => {
let http: HttpClient,
httpTestingController: HttpTestingController,
mockAuthService: AuthorizationService;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule, SharedModule],
providers: [
{
provide: AuthorizationService,
useClass: MockAuthorizationService
},
{
provide: HTTP_INTERCEPTORS,
useClass: AuthorizationInterceptor,
multi: true
},
// One of these tests trigger a console.error call and is expected
// Mocking the logger prevents this otherwise another test run outside this suite
// to prevent console.error calls will fail.
{
provide: LoggerInjectionToken,
useValue: mockLogger
}]
});
http = TestBed.inject(HttpClient);
httpTestingController = TestBed.inject(HttpTestingController);
mockAuthService = TestBed.inject(AuthorizationService);
});
示例测试:
it('will refresh token and re-issue request should 401 be returned.', (() => {
spyOn(mockAuthService, 'requestNewToken').and.callFake(() => {
return of({
renewed: true,
accessToken: 'token'
});
});
http.get('/data')
.subscribe((data) => {
expect(data).toEqual('Payload');
});
const failedRequest = httpTestingController.match('/data')[0];
failedRequest.error(new ErrorEvent('Er'), { status: 401 });
const successReq = httpTestingController.match('/data')[0];
successReq.flush('Payload', { status: 200, statusText: 'OK' });
expect(mockAuthService.requestNewToken).toHaveBeenCalled();
httpTestingController.verify();
}));
直接看需求
下面的代码有助于覆盖 finalize 运算符中的代码。
const next: any = {
handle: () => {
return Observable.create(subscriber => {
subscriber.complete();
});
}
};
const requestMock = new HttpRequest('GET', '/test');
interceptor.intercept(requestMock, next).subscribe(() => {
expect(interceptor.counter).toBeGreaterThan(0);
});