【问题标题】:Angular 11: Unit testing an HttpInterceptor - can't get catchError to work in testAngular 11:对 HttpInterceptor 进行单元测试 - 无法让 catchError 在测试中工作
【发布时间】:2021-03-08 15:29:34
【问题描述】:

我正在努力完成我的 HttpInterceptor 的单元测试。拦截器用作全局错误处理程序,并简单地触发 catchError(httpResponseError)。拦截器在我的网站上运行良好,但我无法通过单元测试来实际测试代码。

这是拦截器的代码:

import { HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable, throwError } from 'rxjs';
import { retry, tap, catchError } from 'rxjs/operators';
import { HttpServiceError } from '../models/httpServiceError.model';
import { LoggingService, LogLevel } from '../services/logging.service';

@Injectable({
    providedIn: 'root'
})

export class HttpResponseInterceptorService implements HttpInterceptor{
  public logLevel!: LogLevel;

  constructor(private readonly loggingService: LoggingService) { 
// Intentionally left blank    
  }

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(request)
      .pipe(
        retry(1),
        tap(() => console.log('ResponseInterceptor called')),
        catchError((error:HttpErrorResponse) => {          
          console.log('HttpErrorResponse caught')
          this.handleHttpError(error);
          return throwError(error);
        }))
  }

  private handleHttpError(error: HttpErrorResponse): Observable<HttpServiceError> {
    const requestError = new HttpServiceError();    
    
    console.log('Error:', error);
    console.log('handleHttpError function called');

    requestError.errorNumber = error.status;
    requestError.statusMessage = error.statusText;

    switch (error.status) {
      case 401: {
        requestError.friendlyMessage = 'You are not logged in';
        break;
      }
      case 403: {
        requestError.friendlyMessage = 'You are not logged in';
        break;
      }
      case 404: {
        requestError.friendlyMessage = 'The service failed to respond';
        break;
      }
      case 429: {
        requestError.friendlyMessage = 'The service is busy';
        break;
      }
      case 500: {
        requestError.friendlyMessage = 'The service is not responding correctly';
        break;
      }      
      default: {
        requestError.friendlyMessage = 'An error occured retrieving the data';
        break;
      }
    }


    this.loggingService.logWithLevel(JSON.stringify(requestError), LogLevel.Information);
    return throwError(requestError);
  }
}

如你所见,我有几个控制台,日志在那里,只有第一个是测试中的触发器。

这是我的规范文件:

import { HttpClient, HttpErrorResponse, HttpEvent, HttpHandler, HttpRequest, HttpResponse, HTTP_INTERCEPTORS } from '@angular/common/http';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { fakeAsync, inject, TestBed } from '@angular/core/testing';
import { of } from 'rxjs';
import { take } from 'rxjs/operators';
import { LoggingService } from '../services/logging.service';

import { HttpResponseInterceptorService } from './httpresponseinterceptor.service';

describe('HttpResponseInterceptorService', () => {
  let interceptor: HttpResponseInterceptorService;  
  let httpMock: HttpTestingController;
  let loggingService: LoggingService;
  let httpClient: HttpClient;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule],
      providers: [        
        {
          provide: HTTP_INTERCEPTORS,
          useClass: HttpResponseInterceptorService,
          multi: true,
        },
      ]
    });
    loggingService = TestBed.inject(LoggingService);     
    interceptor = TestBed.inject(HttpResponseInterceptorService);
    httpMock = TestBed.inject(HttpTestingController);    
    httpClient = TestBed.inject(HttpClient);
  });

  afterEach(() => {
    httpMock.verify();
  });

  it('should be created', () => {
    expect(interceptor).toBeTruthy();
  });

  it('should call loggingService with a friendlyMessage of The service failed to respond (404)', fakeAsync(() => {
    spyOn(loggingService,'logWithLevel');

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

    httpClient.get('/api').subscribe();
   
    let request = httpMock.expectOne("/api");
    request.error(new ErrorEvent('404 Error'), errorResponse);
    // request.flush('Request failed', {status:404, statusText:'Not Found'});
    
    // request.flush(errorResponse);
   
    expect(loggingService.logWithLevel).toHaveBeenCalled();  
  }));

});

我已经尝试过 request.error(new ErrorEvent('404 Error'), errorResponse);// request.flush(errorResponse);:实际上都没有触发 catchError((error:HttpErrorResponse) 代码分支。

非常欢迎好的想法和反馈!

谢谢, 比亚恩

【问题讨论】:

    标签: angular typescript unit-testing karma-jasmine


    【解决方案1】:

    在我看来,您的问题来自“重试(1)”。 如果你想传入catchError 函数,你必须调用numberOfRetry + 1 次你的api。

    也许你可以试试:

        let request = httpMock.expectOne("/api");
        request.error(new ErrorEvent('404 Error first'), errorResponse);
        request = httpMock.expectOne("/api");
        request.error(new ErrorEvent('404 Error second'), errorResponse);
    

    【讨论】:

    • 你摇滚!这就是解决方案。我不认为我的代码实际上像我写的那样工作。非常感谢!作为附带的好处,我还学习了如何对私有函数进行单元测试?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-02
    • 1970-01-01
    • 2021-10-07
    • 2012-05-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多