【问题标题】:RxJS BehaviorSubject getValue inconsistency after value emitted (while testing in Jest)发出值后 RxJS BehaviorSubject getValue 不一致(在 Jest 中测试时)
【发布时间】:2020-01-24 12:04:06
【问题描述】:

我不明白为什么.getValue() 返回 Observable 的默认值,而不是最后发出的值。在测试 Observable 时,它​​正确返回了发出的值。

class TestA {
  readonly aSource: BehaviorSubject<number> = new BehaviorSubject(null);

  getA(): number {
    return this.aSource.getValue();
  }

  promise(): void {
    Promise.reject()
      .catch(() => {
        this.aSource.next(2);

        console.log(this.getA()); // Outputs: 2
      });
  }
}

describe('TestA', () => {
  it('promise', () => {
    const a = new TestA();
    a.promise();

    // Test 1 OK
    expect(a.aSource.asObservable()).toBeObservable(hot('a', {a: 2}));

    // Test 2 FAIL (returns null)
    expect(a.aSource.getValue()).toEqual(2);

    // Test 3 FAIL (returns null)
    expect(a.getA()).toEqual(2);
  });
});

澄清一下,getValue() 方法在测试之外工作得很好,它只会在使用 Jest 测试时失败。

谢谢!

【问题讨论】:

  • 好的,我的假设是 Promise.reject() 将被视为同步代码。

标签: typescript rxjs jestjs rxjs-marbles


【解决方案1】:

即使我执行Promise.reject(),代码也不会同步,因此在这种情况下,您需要刷新执行队列以测试该代码。

使用 Angular 辅助函数的解决方案是:

  it('promise', fakeAsync(() => {
    const a = new TestA();
    a.promise();

    flush();

    expect(a.aSource.asObservable()).toBeObservable(hot('a', {a: 2}));
    expect(a.aSource.getValue()).toEqual(2);
    expect(a.getA()).toEqual(2);
  }));

【讨论】:

    【解决方案2】:

    第一个断言是异步的。在内部,它将解析Observable,因此您确实会得到2

    但是,虽然这是挂起的,但会触发其他两个断言。而且它们是同步的。没有什么可以保证您当时已经完成了.next 呼叫。所以你仍然得到初始值。

    这就是为什么我建议不要使用BehaviorSubject.getValue 方法,而是正确订阅它。这样一来,您就可以通过始终执行异步操作来避免这种混乱。

    【讨论】:

    • 我宁愿不订阅 Observable 做更多包含包装函数的测试,所以由于 Promise.reject() 不同步,我需要刷新微任务,然后它通过所有测试。
    【解决方案3】:

    原因是catch 的回调函数的异步性质。所以我认为如果你将你的期望语句包装在 setTimeout 中,并以异步方式运行测试,它就会变成绿色。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-09-07
      • 1970-01-01
      • 1970-01-01
      • 2021-08-11
      • 2018-08-31
      • 2019-08-31
      • 1970-01-01
      相关资源
      最近更新 更多