作为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个服务的图层:userCardService
和rendezVousService
。
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发出的事件。 expected
和fail
都未执行。我很确定,因为控制台中没有记录任何内容。
我发现传递此测试的唯一方法是不使用运算符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
)。
感谢您的帮助。
答案 0 :(得分:2)
您可以通过将RendezVousResolver
替换为RxJ中的现有行为/函数来简化Observable.create
:
class RendezVousResolver {
searchRendezVous(code: string): Observable<any> {
return this.userCardService.readCard(code)
.mergeMap(userData => this.rendezVousService.search(userData));
}
}
这样你就可以抓住自己的优势了。
通过将readCard
和search
与返回带有预期模拟数据的Rx.Observable.from([])
的模拟交换,可以在没有时间的情况下进行测试。只需在.toPromise()
上调用searchRendezVous()
,就可以在没有任何调度程序魔法的情况下完成工作。
it('returns data', () => {
return searchRendezVous('foo')
.toPromise()
.then(searchResults => {
expect(searchResults).to.not.be.empty();//assert what you need
})
});