Angular2 / RxJS / Jasmine:如何测试Observable链/序列(运算符)

时间:2017-07-17 08:05:35

标签: angular unit-testing jasmine rxjs observable

作为Angular 4项目的一部分,我拼命试图用Jasmine测试一个函数,该函数用运算符实现RxJs链/序列(在我的例子中是map)。

class RendezVousResolver {

  searchRendezVous(code: string): Observable<any> {
    return Observable.create(observer => {
      this.userCardService.readCard(code).map(userData => {
        this.rendezVousService.search(userData).subscribe(
          result => {
            observer.next(result);
          },
          error => {
            observer.error(error);
          }
        );
      });
    });
  }

}

我的单元测试使用2次模拟来“模拟”2个服务的图层:userCardServicerendezVousService

class MockUserCardService {

  readCard(code: string): Observable<any> {
    return Observable.of('<data></data>');
  }

}

class MockRendezVousService {

  search(userData : string): Observable<any> {
    return Observable.of({
      rdvs: []
    });
  }

}

beforeEach(() => {
  TestBed.configureTestingModule({
    providers: [
      RendezVousResolver,
      { provide: RendezVousService, useClass: MockRendezVousService },
      { provide: SwcVitaleReadingService, useClass: MockSwcVitaleReadingService }
    ]
  });
  fixture = TestBed.get(RendezVousResolver);
});

这是我的单元测试。

it('should return the expected response', async(() => {
  fixture.resolve(undefined, undefined).subscribe(
    rdvs => {
      console.log("expect");
      expect(rdvs).toEqual({
        rdvs: []
      });
    },
    error => {
      console.log("fail");
      fail('No error was expected');
    }
  );
}));

当我执行它时,测试似乎不等待被模拟的Observable发出的事件。 expectedfail都未执行。我很确定,因为控制台中没有记录任何内容。

我发现传递此测试的唯一方法是不使用运算符map并用嵌套订阅替换我的代码。

searchRendezVous(code: string): Observable<any> {
  return Observable.create(observer => {
    this.userCardService.readCard(code).subscribe(
      userData => {
        this.rendezVousService.search(userData).subscribe(
          rdvs => {
            observer.next(rdvs);
          },
          error => {
            observer.error(error);
          }
        )
      },
      error => {
        observer.error(error);
      }
    );
  });
}

我遇到了与其他运营商相同的问题而不是map(例如zip)。

感谢您的帮助。

1 个答案:

答案 0 :(得分:2)

您可以通过将RendezVousResolver替换为RxJ中的现有行为/函数来简化Observable.create

class RendezVousResolver {
  searchRendezVous(code: string): Observable<any> {
    return this.userCardService.readCard(code)
      .mergeMap(userData => this.rendezVousService.search(userData));
  }
}

这样你就可以抓住自己的优势了。

通过将readCardsearch与返回带有预期模拟数据的Rx.Observable.from([])的模拟交换,可以在没有时间的情况下进行测试。只需在.toPromise()上调用searchRendezVous(),就可以在没有任何调度程序魔法的情况下完成工作。

it('returns data', () => {
  return searchRendezVous('foo')
    .toPromise()
    .then(searchResults => {
      expect(searchResults).to.not.be.empty();//assert what you need
    })
});