我正在尝试对自定义RxJS运算符进行单元测试。该操作符非常简单,它使用RetryWhen重试失败的HTTP请求,但是有一个延迟,并且仅当HTTP Error在500范围内时才重试。使用茉莉花,这是在Angular应用程序中。
我已经看过了:
不幸的是,更新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))
))
);
}
我想证明它可以订阅一个可观察对象,该对象在第一次尝试时会返回错误,但随后会返回成功的响应。最终订阅应显示可观察到的成功值。
预先感谢您提供任何见解。
答案 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);
}