单位测试角度2的可观测值

单元测试服务的正确方法是什么,返回角度2的可观测结果?假设我们在 CarService 服务类中有一个 getCars 方法:

...
export class CarService{
...
getCars():Observable<any>{
return this.http.get("http://someurl/cars").map( res => res.json() );
}
...
}

如果我尝试用以下方式编写测试,我会得到警告: “规格没有期望”:

it('retrieves all the cars', inject( [CarService], ( carService ) => {
carService.getCars().subscribe( result => {
expect(result.length).toBeGreaterThan(0);
} );
}) );

使用 injectAsync 没有帮助,因为据我所知,它可以处理 Promise对象。

126241 次浏览

不推荐使用 AsyncTestCompleterinjectAsync替换了它 Https://github.com/angular/angular/issues/4715#issuecomment-149288405
但是 injectAsync现在也被废弃了
injectAsync不再被弃用 https://github.com/angular/angular/pull/5721(请参阅@ErdincGuzel 的评论)

it('retrieves all the cars', injectAsync( [CarService], ( carService ) => {
var c = PromiseWrapper.completer();
carService.getCars().subscribe( result => {
expect(result.length).toBeGreaterThan(0);
c.resolve();
} );
return c.promise;
}) );

最后,我以一个工作示例作为结束。Observable类有一个方法 toRank,可以将一个可观察的对象转换为一个承诺对象。正确的方法应该是:

it('retrieves all the cars', injectAsync( [CarService], ( carService ) => {
return carService.getCars().toPromise().then( (result) => {
expect(result.length).toBeGreaterThan(0);
} );
}) );

但是,虽然上面的代码可以处理任何可观察对象,但是我仍然存在从 Http 请求返回的 Observable的问题,这可能是一个 bug。下面是一个柱塞展示上面的情况: < a href = “ http://plnkr.co/edit/ak2qZH685QzTN6RoK71H? p = 预览”rel = “ norefrer”> http://plnkr.co/edit/ak2qzh685qztn6rok71h?p=preview

更新:
在 beta.14版本中,似乎可以正确地使用所提供的解决方案。

Angular(2 + 版本)的正确方法:

it('retrieves all the cars', waitForAsync(inject([CarService], (carService) => {
carService.getCars().subscribe(result => expect(result.length).toBeGreaterThan(0));
}));

异步可观测数据与同步可观测数据

重要的是要理解,可观测数据可以是 同步或异步的

在您的特定示例中,观察对象是 异步的(它包装了一个 http 调用)。
因此,您必须使用 waitForAsync函数,该函数在一个特殊的 异步测试区异步测试区中执行其主体内的代码。它拦截并跟踪在其主体中创建的所有承诺,使得在异步操作完成时期望测试结果成为可能。

然而,如果你的观察值是 同步,例如:

...
export class CarService{
...
getCars():Observable<any>{
return Observable.of(['car1', 'car2']);
}
...

你将不需要 waitForAsync函数,你的测试将变得简单

it('retrieves all the cars', inject([CarService], (carService) => {
carService.getCars().subscribe(result => expect(result.length).toBeGreaterThan(0));
});

弹珠

在测试一般观测值和特别是角度观测值时需要考虑的另一个因素是 弹珠测试

您的示例非常简单,但是通常逻辑比仅仅调用 http服务和测试这种逻辑要复杂得多。
大理石使测试非常短,简单和全面(它是特别有用的测试 Ngrx 效应)。

如果您使用的是 Jasmine,您可以使用 茉莉花球,对于 Jest开玩笑的,但是如果您喜欢其他的东西,有 Rxjs-marbles,这应该与任何测试框架兼容。

这里 是用大理石复制和修复竞态条件的一个很好的例子。


测试指南

我推荐这种方法,我认为它更优雅:

expectAsync(carService.getCars().toPromise()).toBeResolvedWith(myExpectedValue);

还可以使用 Jasmine Matcher提供自己的异步匹配器

我设法让它工作的方法是在期望之后订阅和调用。

it('should equal bar', (done: any) => {
bar.getFoo().subscribe(v => {
expect(v).toBe('foo');
done();
});
});