【问题标题】:Expected object to be a kind of ScalarObservable, but was Observable预期的对象是一种 ScalarObservable,但它是 Observable
【发布时间】:2018-05-08 19:30:13
【问题描述】:

在我的 Angular 应用程序中,我使用 Observables 的方式如下:

getItem(id): Observable<Object> {
  return this.myApi.myMethod(...); // returns an Observable
}

我对它进行了单元测试:

it('getItem(...) should correctly do its job',
  inject([MyService], (service: MyService) => {

    const spy = spyOn(myApi, 'myMethod').and.returnValue(mockObservable);

    const mockObservable = Observable.of('mock');

    expect(service.getItem(123)).toEqual(mockObservable);

    expect(spy).toHaveBeenCalledWith(...);
  })
);

而且效果很好。

但是,如果我尝试使用 catchdefault error-handling logic 添加到我的 getItem() 方法中:

getItem(id): Observable<Object> {
  return this.myApi.myMethod(...).catch(e => {
    /* display a notification error ... */
    return Observable.throw(e);
  });
}

它仍然可以正常工作,但现在测试失败了,说:

预期的对象是一种 ScalarObservable,但实际上是 Observable({ _isScalar: false, source: ScalarObservable({ _isScalar: true, value: 'mock', scheduler: null }), operator: CatchOperator({ selector: Function , 捕获: }) }).

这是什么意思?为什么会这样?我该如何解决这个问题?

【问题讨论】:

  • catch 是一个运算符,因此它返回一个新的 observable 以及您期望的 observable,因为它是 source。这就是运营商的实现方式。
  • 扩展@cartant 的评论。检查expect(service.getItem(123)).toEqual(mockObservable) 失败,因为它们不是同一个对象。 service 方法返回一个新的 observable 包装 mockObservable ,因此检查失败。您的测试最好订阅从您的服务调用返回的 observable 并确保它返回 'mock'
  • 感谢@Pace,这实际上解决了我的问题。

标签: typescript jasmine rxjs angular-observable angular-test


【解决方案1】:

感谢@Pace 的输入:

expect(service.getItem(123)).toEqual(mockObservable) 失败是因为 它们不是同一个对象。服务方法正在返回一个新的 包装 mockObservable 的 observable ,因此检查失败。你的测试 订阅从你返回的 observable 会更好 服务调用并确保它返回'mock'

我找到了解决办法:

it('getItem(...) should correctly do its job',
  inject([MyService], (service: MyService) => {

    const spy = spyOn(myApi, 'myMethod').and.returnValue(mockObservable);

    const mockData = 'mock'; // can be anything
    const mockObservable = Observable.of(mockData);


    service.getItems().subscribe((data) => {
      expect(data).toEqual(mockData);
    });

    expect(spy).toHaveBeenCalledWith(...);
  })
);

【讨论】:

  • 这种测试要小心。如果从 getItems 返回的 observable 是异步的,那么 expect 可能永远不会被调用。例如,您可以将getItems 更改为this.myApi.myMethod(...).map(() =&gt; 'not-mock').delay(500);,测试仍然会通过。一种解决方法是将expect 更改为...return service.getItems().do(() =&gt; { expect(data).toEqual(mockData); }).toPromise() 并使用jasmine-promise 之类的内容。还有其他方法可以做到这一点。
猜你喜欢
  • 1970-01-01
  • 2022-01-02
  • 2022-01-05
  • 2022-07-05
  • 1970-01-01
  • 2022-06-10
  • 2023-03-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多