如何测试 Observable<boolean>

How to test an Observable<boolean>

我有一个条件 returns 如下所示的 Observable:

app.component.ts


  import { Observable } from "rxjs";
    
  export class ProductComponent implements OnInit

        ProductListLength: Number;
        isProductListEmpty: Observable<boolean>; 
    }
    
    ngOnInit(): void {

        if(this.ProductListLength === 0)
        this.isProductListEmpty = new Observable((observer) => observer.next(true))
    } 
        else {
        this.isProductListEmpty = new Observable((observer) => observer.next(false))
    }

我尝试运行这些测试用例:

app.component.spec.ts


it('should return true when List is empty', () => {

   component.productListLength = 0
   fixture.detectChanges()

   expect(component.isProductListEmpty).toBeTrue()
})

it('should return false when List not empty', () => {

   component.productListLength = 2
   fixture.detectChanges()

   expect(component.isProductListEmpty).toBeFalse()
})

但是 运行ning ng test 我收到了这个: 错误:预期 Observable({_isScalar: false, _subscribe: Function}) 为真

如何正确测试这些案例?

您需要从可观察对象中获取值。您可以订阅它或使用异步等待。像下面这样的东西应该可以工作(未经测试)。

it('should return false when List not empty', async () => {

   component.productListLength = 2
   fixture.detectChanges();
   const res = await component.isProductListEmpty.toPromise();
   expect(res).toBeFalse()
})

编辑(应该可以解决超时问题)

it('should return false when List not empty', async () => {

   component.productListLength = 2
   component.ngOnInit();
   const res = await component.isProductListEmpty.toPromise();
   expect(res).toBeFalse()
})

您可以通过使用测试参数告诉它何时完成来使您的测试异步:

it('should return true when List is empty', (done) => {

   component.productListLength = 0
   fixture.detectChanges()

   component.isProductListEmpty.subscribe(val => {
     expect(val).toBeTrue();
     done();
   });
})

要添加到 Daniel Douglas 答案,我认为您需要使用 take 运算符。

import { take } from 'rxjs/operators';

it('should return false when List not empty', async () => {

   component.productListLength = 2
   fixture.detectChanges();
   const res = await component.isProductListEmpty.pipe(take(1)).toPromise();
   expect(res).toBeFalse()
})

我们必须 take(1) 因为我们采用第一个发射然后转换为承诺。您收到超时错误是因为如果您不进行第一次发射,承诺将永远不会解决(它会挂起)。

我也希望 fixture.detectChanges() 是您在测试套件中调用的第一个为您调用 ngOnInit 的人。否则,每次更新 isProductListEmpty.

时都必须手动调用 ngOnInit