1

我正在尝试对自定义 RxJS 运算符进行单元测试。操作符很简单,它使用 RetryWhen 重试失败的 HTTP 请求,但有延迟,只有在 HTTP Error 在 500 范围内时才会重试。使用 jasmine,这是在 Angular 应用程序中。

我看过这个:

带有 retryWhen 的 rxjs 单元测试

不幸的是,更新 SpyOn 调用似乎并没有改变连续重试返回的 observable。每次重试时,它都会使用原始间谍值重试。

我还查看了一堆 rxjs 弹珠示例,但似乎都不起作用。我不确定是否可以在这里使用 rxjs 弹珠,因为(AFAIK)无法模拟您首先提交错误的 observable,然后在后续尝试中提交成功的 observable 的情况。

该代码基本上是这个的克隆: https ://blog.angularindepth.com/retry-failed-http-requests-in-angular-f5959d486294

export function delayedRetry(delayMS: number, maxRetry) {
    let retries = maxRetry;

    return (src: Observable<any>) =>
        src.pipe(
            retryWhen((errors: Observable<any>) => errors.pipe(
                delay(delayMS),
                mergeMap(error =>
                    (retries-- > 0 && error.status >= 500) ? of(error) : throwError(error))

            ))
        );
}

我希望能够证明它可以订阅一个在第一次尝试时返回错误但随后返回成功响应的 observable。最终订阅应该显示 observable 发出的任何成功值。

提前感谢您的任何见解。

4

3 回答 3

3

尝试使用这个 observable 作为源 observable 来测试

const source = (called,successAt)=>{
  return defer(()=>{
  if(called<successAt){
    called++
  return throwError({status:500})
  }
  else return of(true)
  })
  }

测试

this.delayedRetry(1000,3)(source(0,3)).subscribe()
于 2019-08-09T07:59:06.730 回答
1

要测试重试功能,您需要一个 observable,每次调用它时都会发出不同的事件。例如:

let alreadyCalled = false;
const spy = spyOn<any>(TestBed.inject(MyService), 'getObservable').and.returnValue(
  new Observable((observer) => {
    if (alreadyCalled) {
      observer.next(message);
    }
    alreadyCalled = true;
    observer.error('error message');
  })
);

这个 observable 将首先发出一个错误,然后是下一个事件。

您可以检查,如果您的 observable 收到这样的消息:

it('should retry on error', async(done) => {
    let alreadyCalled = false;
    const spy = spyOn<any>(TestBed.inject(MyDependencyService), 'getObservable').and.returnValue(
      new Observable((observer) => {
        if (alreadyCalled) {
          observer.next(message);
        }
        alreadyCalled = true;
        observer.error('error message');
      })
    );
    const observer = {
      next: (result) => {
        expect(result.value).toBe(expectedResult);
        done();
      }
    }

    subscription = service.methodUnderTest(observer);
    expect(spy).toHaveBeenCalledTimes(1);
}
于 2021-03-05T09:51:51.603 回答
0

基于先前的答案,我一直在使用它,这使您可以更好地控制返回的内容。

const source = (observables) => {
  let count = 0;
  return defer(() => {
    return observables[count++];
  });
};

然后可以像这样使用

const obsA = source([
  throwError({status: 500}),
  of(1),
]);

或者它可以与 rxjs 弹珠一起使用,例如

const obsA = source([
  cold('--#', null, { status: 500 }),
  cold('--(a|)', { a: 1 }),
]);
于 2021-01-06T21:38:45.690 回答