【问题标题】:How to unit test an HTTP interceptor in Angular using Jasmine如何使用 Jasmine 在 Angular 中对 HTTP 拦截器进行单元测试
【发布时间】:2021-11-05 02:13:47
【问题描述】:

我的 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 方法。请求帮助。

【问题讨论】:

  • 使用httpMock 执行请求并检查实际请求/响应。 angular.io/guide/http#testing-http-requests
  • 它没有显示任何覆盖的代码,因为您没有在规范中运行任何该代码。您提供的所有代码都没有明显的错误,您的问题也没有,所以请用您尝试过的实际错误或代码更新您的问题,解释什么不符合您的期望。
  • 我已经更新了规范代码。我可以用上面更新的代码覆盖几行代码,但我仍然无法覆盖 finalize 方法。任何人都可以在这里提供帮助。

标签: angular unit-testing jasmine angular-http-interceptors


【解决方案1】:

从提供程序中删除HttpInterceptorService,因为您已经在下一行使用{ provide:HTTP_INTERCEPTOR, ... 提供它。尝试遵循本指南:https://alligator.io/angular/testing-http-interceptors/。似乎您需要有一个实际进行 API 调用的服务。尝试遵循本指南: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);
      });
   });
});

【讨论】:

  • 共享链接很有用。我已经用它更新了代码,我能够覆盖几行代码,但我仍然无法覆盖 finalize 方法中的行。你能帮忙覆盖这些代码行吗?
  • 我添加了一个编辑。看看它是否有效。我认为它应该可以工作。
  • 我已经尝试过了,但它没有涵盖代码的 finalize 运算符部分。
  • 对不起,我不确定。我记得我遇到了单元测试拦截器的问题,在我的断言之后将应用标头。
  • 我得到了一个解决方案并更新了与答案相同的解决方案。谢谢!
【解决方案2】:

生活榜样@

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();
}));

直接看需要什么

【讨论】:

    【解决方案3】:

    下面的代码有助于覆盖 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);
    });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-05-10
      • 1970-01-01
      • 1970-01-01
      • 2018-12-05
      • 1970-01-01
      • 1970-01-01
      • 2014-08-15
      • 1970-01-01
      相关资源
      最近更新 更多