使用 retry() 和 HttpClientTestingModule 测试 HTTP 请求

Testing an HTTP request with retry() and HttpClientTestingModule

我想用 HttpClientTestingModule 测试 HTTP 调用错误响应。这工作正常,直到我将 rxjs retry(2) 添加到 HTTP 调用。然后,测试明显报错说发现了一个意外的请求:

Expected no open requests, found 1

但是现在,我不知道如何使用 HttpTestingController:

来期待两个请求

service.ts

@Injectable()
export class Service {
  constructor(private http: HttpClient) { }

  get() {
    return this.http.get<any>('URL')
      .pipe(
        retry(2),
        catchError(error => of(null))
      )
  }
}

service.spec.ts

describe('Service', () => {
  let httpTestingController: HttpTestingController;
  let service: Service;

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [Service],
      imports: [HttpClientTestingModule]
    });

    httpTestingController = TestBed.get(HttpTestingController);
    service = TestBed.get(Service);
  });

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

  it('should handle 404 with retry', () => {
    service.get().subscribe((data: any) => {
      expect(data).toBe(null);
    });
    expectErrorResponse(404);
  });

  function expectErrorResponse(status: number) {
    const requests = httpTestingController.match('URL');
    // fails -> finds only one request
    expect(requests.length).toBe(2);
    requests.forEach(req => req.flush('error', {status, statusText: 'Not Found'}));
  }
});

如果我删除 expect(requests.length).toBe(2),测试将失败并显示之前的错误消息。

运行 例子

你可以试试这个Stackblitz

The fundamentals of Angular - HttpClient - retry() 状态:

The RxJS library offers several retry operators that are worth exploring. The simplest is called retry() and it automatically re-subscribes to a failed Observable a specified number of times. Re-subscribing to the result of an HttpClient method call has the effect of reissuing the HTTP request.

所以每次调用 flush 时它都会留下一个打开的请求。您只需要在服务重试请求时重复请求处理和刷新次数。

it('can test for 404 error', () => {
  const emsg = 'deliberate 404 error';

  testService.getData().subscribe(
    data => fail('should have failed with the 404 error'),
    (error: HttpErrorResponse) => {
      expect(error.status).toEqual(404, 'status');
      expect(error.error).toEqual(emsg, 'message');
    }
  );

  const retryCount = 3;
  for (var i = 0, c = retryCount + 1; i < c; i++) {
    let req = httpTestingController.expectOne(testUrl);
    req.flush(emsg, { status: 404, statusText: 'Not Found' });
  }
});