如何测试有延迟的递归 http 请求?
How can I test recursive http requests that have a delay?
我的情况有点复杂,对于后端实现,我需要轮询后端直到
- 我从 BE
获得了成功状态
- 我从 BE
得到失败状态
- 我继续进行的时间超过了我的重试次数(客户端 TO)
代码有效,针对后端的测试在所有三种情况下均成功。我也成功地测试了第一种和第二种情况,如果结果是瞬时的(模拟完成/立即失败的响应,中间没有得到 onGoing
)。但是,我无法测试第三种情况。每次尝试我都会遇到不同的错误,所以现在我转向 S.O 的集体思想。寻求帮助:-)
ts 文件:
doAction(content): Observable<resPassType> {
return this.postAction(content) // private function that just calls HTTP Post at url1, and returns an actionId for polling
.pipe(concatMap(action => this.poll(action))); // see below
}
private poll(action, retryCount = config.retryCount): Observable<resPassType>{
return time(config.retryTime).pipe(switchMap(() =>
this.getActionStatus(action) // private function that calls HTTP get at url2/action.id
.pipe(concatMap ( res=> {
retryCount--;
if(retryCount < 0)
return throwError('Action Timed Out'); // this is essentially what I want to test
switch(res.action.state.toLowerCase()) {
case 'completed':
return of(resPassTypeData);//taken from within res.action. Successfully tested
case 'failed':
return throwError('Action Failed'); // successfully tested
case 'ongoing':
return this.poll(res.action, retryCount)
default':
return throwError('unexpeceted action state');
}
}))));
}
看到成功的测试可能会帮助你帮助我,所以这里包括失败的测试
it('should throw error if action failed`, fakeAsync(()=>{
const mockGetActionResponse = {'action' : {'id' : mockActionId, state: 'Failed' }};
service.doAction(mockContent).subscribe(
() => {},
err => expect(err).toEqual('Action Failed');
);
const postCall = httpTestingController.expectOne(url1);
expect(postCall.request.method).toEqual('POST');
expect(postCall.request.body).toEqual(mockContent);
postCall.flush(mockPostActionResponse);
tick(config.retryTime);
const getCall = httpTestingController.expectOne(url2/mockActionId);
expect(getCall .request.method).toEqual('Get');
getCall.flush(mockGetActionResponse );
}));
这个测试有效。如何为案例 3 编写测试?编写相同的测试并将状态更改为 'onGoing' 并更改错误预期给我留下了错误
error expected no open requests found 1
我的直觉是这与递归或延迟或其他原因有关,因为这是 poll
被多次调用的唯一测试用例。任何线索将不胜感激:-)
编辑
由于@Andrei 的评论和改进,代码已更新。问题仍然存在
@Andrei 在评论中找到的答案。
现在的工作代码如下所示:
it('should throw error if action timed out',()=>{
const mockGetActionResponse = {'action' : {'id' : mockActionId, state: 'onGoing' }};
service.doAction(mockContent).subscribe(
() => {},
err => expect(err).toEqual('Action Timed Out');
);
const postCall = httpTestingController.expectOne(url1);
expect(postCall.request.method).toEqual('POST');
expect(postCall.request.body).toEqual(mockContent);
postCall.flush(mockPostActionResponse);
for( let i=0; i<config.retryCount; i++) {
tick(config.delayTime);
const getCall = httpTestingController.expectOne(url2);
expect(getCall.request.method).toEqual('GET');
getCall.flush(mockGetActionResponse)
}
})
我的情况有点复杂,对于后端实现,我需要轮询后端直到
- 我从 BE 获得了成功状态
- 我从 BE 得到失败状态
- 我继续进行的时间超过了我的重试次数(客户端 TO)
代码有效,针对后端的测试在所有三种情况下均成功。我也成功地测试了第一种和第二种情况,如果结果是瞬时的(模拟完成/立即失败的响应,中间没有得到 onGoing
)。但是,我无法测试第三种情况。每次尝试我都会遇到不同的错误,所以现在我转向 S.O 的集体思想。寻求帮助:-)
ts 文件:
doAction(content): Observable<resPassType> {
return this.postAction(content) // private function that just calls HTTP Post at url1, and returns an actionId for polling
.pipe(concatMap(action => this.poll(action))); // see below
}
private poll(action, retryCount = config.retryCount): Observable<resPassType>{
return time(config.retryTime).pipe(switchMap(() =>
this.getActionStatus(action) // private function that calls HTTP get at url2/action.id
.pipe(concatMap ( res=> {
retryCount--;
if(retryCount < 0)
return throwError('Action Timed Out'); // this is essentially what I want to test
switch(res.action.state.toLowerCase()) {
case 'completed':
return of(resPassTypeData);//taken from within res.action. Successfully tested
case 'failed':
return throwError('Action Failed'); // successfully tested
case 'ongoing':
return this.poll(res.action, retryCount)
default':
return throwError('unexpeceted action state');
}
}))));
}
看到成功的测试可能会帮助你帮助我,所以这里包括失败的测试
it('should throw error if action failed`, fakeAsync(()=>{
const mockGetActionResponse = {'action' : {'id' : mockActionId, state: 'Failed' }};
service.doAction(mockContent).subscribe(
() => {},
err => expect(err).toEqual('Action Failed');
);
const postCall = httpTestingController.expectOne(url1);
expect(postCall.request.method).toEqual('POST');
expect(postCall.request.body).toEqual(mockContent);
postCall.flush(mockPostActionResponse);
tick(config.retryTime);
const getCall = httpTestingController.expectOne(url2/mockActionId);
expect(getCall .request.method).toEqual('Get');
getCall.flush(mockGetActionResponse );
}));
这个测试有效。如何为案例 3 编写测试?编写相同的测试并将状态更改为 'onGoing' 并更改错误预期给我留下了错误
error expected no open requests found 1
我的直觉是这与递归或延迟或其他原因有关,因为这是 poll
被多次调用的唯一测试用例。任何线索将不胜感激:-)
编辑 由于@Andrei 的评论和改进,代码已更新。问题仍然存在
@Andrei 在评论中找到的答案。
现在的工作代码如下所示:
it('should throw error if action timed out',()=>{
const mockGetActionResponse = {'action' : {'id' : mockActionId, state: 'onGoing' }};
service.doAction(mockContent).subscribe(
() => {},
err => expect(err).toEqual('Action Timed Out');
);
const postCall = httpTestingController.expectOne(url1);
expect(postCall.request.method).toEqual('POST');
expect(postCall.request.body).toEqual(mockContent);
postCall.flush(mockPostActionResponse);
for( let i=0; i<config.retryCount; i++) {
tick(config.delayTime);
const getCall = httpTestingController.expectOne(url2);
expect(getCall.request.method).toEqual('GET');
getCall.flush(mockGetActionResponse)
}
})