如何在rxjs中对retryWhen运算符进行单元测试?

时间:2019-08-08 15:10:44

标签: unit-testing rxjs retrywhen

我正在尝试对自定义RxJS运算符进行单元测试。该操作符非常简单,它使用RetryWhen重试失败的HTTP请求,但是有一个延迟,并且仅当HTTP Error在500范围内时才重试。使用茉莉花,这是在Angular应用程序中。

我已经看过了:

rxjs unit test with retryWhen

不幸的是,更新SpyOn调用似乎并不会更改在连续重试中返回的可观察值。每次重试时,都会使用原始的spyon值重试。

我也看了很多rxjs大理石示例,但似乎都没有用。我不确定是否可以在这里使用rxjs大理石,因为(AFAIK)无法模拟先提交错误的可观测值,然后在随后的尝试中成功提交可观测值的情况。

代码基本上是此代码的克隆: 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))

            ))
        );
}

我想证明它可以订阅一个可观察对象,该对象在第一次尝试时会返回错误,但随后会返回成功的响应。最终订阅应显示可观察到的成功值。

预先感谢您提供任何见解。

3 个答案:

答案 0 :(得分:0)

尝试将此可观察值用作可观察的源进行测试

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

答案 1 :(得分: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 }),
]);

答案 2 :(得分:0)

要测试重试功能,您需要一个可在每次调用时发出不同事件的 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);
}