【问题标题】:How can I unit test a retryWhen operator in rxjs?如何在 rxjs 中对 retryWhen 运算符进行单元测试?
【发布时间】:2019-08-08 15:10:44
【问题描述】:

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

我看过这个:

rxjs unit test with retryWhen

不幸的是,更新 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 发出的任何成功值。

提前感谢您提供任何见解。

【问题讨论】:

    标签: unit-testing rxjs retrywhen


    【解决方案1】:

    尝试使用这个 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()
    

    【讨论】:

    • 帮助了我,我不知道你可以用源代码做到这一点,酷。
    【解决方案2】:

    要测试重试功能,您需要一个 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);
    }
    

    【讨论】:

      【解决方案3】:

      在之前的答案的基础上,我一直在使用它,它可以让您更好地控制返回的内容。

      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 }),
      ]);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-05-20
        • 2023-03-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-12-27
        • 1970-01-01
        相关资源
        最近更新 更多