Rxjs 单元测试NestJS可观察Http重试
我正在通过NestJS的内置HttpService向第三方API发出请求。我试图模拟这样一个场景:对这个api的一个端点的初始调用可能会在第一次尝试时返回一个空数组。我想使用RxJS的Rxjs 单元测试NestJS可观察Http重试,rxjs,jestjs,nestjs,Rxjs,Jestjs,Nestjs,我正在通过NestJS的内置HttpService向第三方API发出请求。我试图模拟这样一个场景:对这个api的一个端点的初始调用可能会在第一次尝试时返回一个空数组。我想使用RxJS的retryWhen在延迟1秒后再次点击api。我目前无法让单元测试模拟第二个响应,但是: it('Retries view account status if needed', (done) => { jest.spyOn(httpService, 'post') .mockReturnV
retryWhen
在延迟1秒后再次点击api。我目前无法让单元测试模拟第二个响应,但是:
it('Retries view account status if needed', (done) => {
jest.spyOn(httpService, 'post')
.mockReturnValueOnce(of(failView)) // mock gets stuck on returning this value
.mockReturnValueOnce(of(successfulView));
const accountId = '0812081208';
const batchNo = '39cba402-bfa9-424c-b265-1c98204df7ea';
const response =client.viewAccountStatus(accountId, batchNo);
response.subscribe(
data => {
expect(data[0].accountNo)
.toBe('0812081208');
expect(data[0].companyName)
.toBe('Some company name');
done();
},
)
});
我的实施是:
viewAccountStatus(accountId: string, batchNo: string): Observable<any> {
const verificationRequest = new VerificationRequest();
verificationRequest.accountNo = accountId;
verificationRequest.batchNo = batchNo;
this.logger.debug(`Calling 3rd party service with batchNo: ${batchNo}`);
const config = {
headers: {
'Content-Type': 'application/json',
},
};
const response = this.httpService.post(url, verificationRequest, config)
.pipe(
map(res => {
console.log(res.data); // always empty
if (res.status >= 400) {
throw new HttpException(res.statusText, res.status);
}
if (!res.data.length) {
this.logger.debug('Response was empty');
throw new HttpException('Account not found', 404);
}
return res.data;
}),
retryWhen(errors => {
this.logger.debug(`Retrying accountId: ${accountId}`);
// It's entirely possible the first call will return an empty array
// So we retry with a backoff
return errors.pipe(
delayWhen(() => timer(1000)),
take(1),
);
}),
);
return response;
}
每次跑步时。。。所以我猜我没有在正确的位置调用
done()
我认为问题在于retryWhen(notifier)
将在其notifier
发出时重新订阅同一来源
意思是如果你有
新的可观察对象(s=>{
s、 下一步(1);
s、 其次(2);
s、 错误(新错误('err!'));
}).烟斗(
retryWhen(/*…*/)
)
每次重新订阅源时都会调用回调。在您的示例中,它将调用负责发送请求的逻辑,但不会再次调用post
方法
源代码可以被认为是可观察的
的回调:s=>{…}
我认为您必须做的是根据错误是否发生有条件地选择源
也许你可以使用:
让hasErr=false;
jest.spyOn(httpService,'post')
A.实施(
()=>hasErr?of(成功视图):(hasErr=true,of(失败视图))
)
编辑
我认为上面没有什么不同,我认为mockImplementation
应该是什么样子的:
让err=false;
模拟实现(
()=>新的可观测数据=>{
如果(错误){
s、 下一步(成功)
}
否则{
错误=正确;
s、 下一个(失败)
}
})
)
我想肯定是在“重新订阅”部分。话虽如此,在现实生活中,这篇文章将不得不再次被调用,所以我需要找到一些方法来实现这一点。我确实尝试了您的建议,但它与调用.mockReturnValueOnce()
的效果相同。该实现确实运行了多次,但它永远不会到达第二个“successfulView”。因为我不能证明这会做我认为它应该做的事情,我不能很遗憾地发货。我将返回到一个基于承诺的解决方案,并了解有关可观察对象的更多信息。在此之前,请尝试以下操作:mockImplementation(()=>newobservate(s=>{if(err){s.next(success)}else{err=true;s.next(fail)}))
。我担心的是,它实际上不会再给邮局打电话了。在实际场景中,我希望发布/重试端点。我当然很感激你的回答,因为它能帮助我理解更多。真正的秘密在于next()
想象一下http.post
只返回newobservable(s=>fetch(…),然后(…)。然后(r=>s.next(r))
。可观察对象的回调是源retryWhen
将重新订阅该流。。。这就是为什么不再调用post
方法的原因。在实际场景中,虽然它不会再次调用该方法,但它会重新调用该方法创建的逻辑,因此本质上是一样的。此外,如果您想了解更多关于HttpClientModule
及其工作原理的信息,可以查看。
: Timeout - Async callback was not invoked within the 5000ms timeout specified by jest.setTimeout.Timeout - Async callback was not invoked within the 5000ms timeout specified by jest.setTimeout.Error: