如何在Angular中创建可观察的模拟来测试http rxjs retry / retryWhen?

时间:2018-07-18 10:34:43

标签: angular jasmine rxjs

我的角度应用程序中有一个以下形式的http请求:this.http.get(url,options).pipe(retry(5))

我想使用茉莉花对此进行单元测试,以便http请求首先返回一个错误,但是在随后的尝试中,返回期望的数据。

我以前按照angular.io文档spyOn(http,'get').and.returnValue(defer(() => Promise.reject(errorObject)));

的建议以这种格式返回了http错误。

rxjs运算符重试似乎没有再次调用http.get函数,因此更改间谍程序的返回值不起作用。我认为我需要做的是以某种方式从间谍返回一个可观察的对象,该对象首先发出错误,然后发出数据。我曾考虑过使用BehaviorSubject,但不认为它会接受要传递的错误。

有什么办法可以做到这一点?

2 个答案:

答案 0 :(得分:1)

如果我们转到角度source code,我们将看到下一个:

<div class="imgslide noselect">
  <div class="prev" onclick="plusDivs('project1', -1)"></div>
  <div class="next" onclick="plusDivs('project1', 1)"></div>
  <img class="slides" alt="image1" src="img/project-1/Scan-4.jpg">
  <img class="slides" alt="image2" src="img/project-1/Scan-8.jpg">
  <img class="slides" alt="image3" src="img/project-1/Scan-24.jpg">
  <img class="slides" alt="image4" src="img/project-1/Scan-35.jpg">
  <img class="slides" alt="image5" src="img/project-1/Scan-39.jpg">
  <img class="slides" alt="image6" src="img/project-1/Scan-40.jpg">
</div>
<div class="img-name"></div>

为了使请求可重试,他们以of(req)开头,因此我们可以在单元测试中执行相同的操作来模拟此行为。例如:

// Start with an Observable.of() the initial request, and run the handler (which
// includes all interceptors) inside a concatMap(). This way, the handler runs
// inside an Observable chain, which causes interceptors to be re-run on every
// subscription (this also makes retries re-run the handler, including interceptors).
const events$: Observable<HttpEvent<any>> =
    of (req).pipe(concatMap((req: HttpRequest<any>) => this.handler.handle(req)));

createRetriableStream函数的外观如下:

spyOn(http,"get").and.returnValue(
    createRetriableStream(
       throwError("err"),
       throwError("err"),
       throwError("err"),
       of("a")
    )
);

通常,重试逻辑与尝试之间的延迟一起使用,以涵盖可以使用time progression syntax的这一部分。因此您的测试可能类似于:

function createRetriableStream(...resp$: any): any {
   let fetchData: Spy = createSpy("fetchData");
   fetchData.and.returnValues(...resp$);
   return of(undefined).pipe(switchMap((_) => fetchData()));
}

答案 1 :(得分:0)

可以请您尝试以下方法。您还可以发布该功能的完整代码吗?

it('should check for the get error call ', () => {
            spyOn(http, 'get').and.returnValue(Observable.throw('error'));
            fixture.detectChanges() // or component.function()
            expect(http.get).toHaveBeenCalled();
        });