0

如何对这个 Observable 进行单元测试?

e1.pipe(
    concatMap(x => of(x).pipe(withLatestFrom(e2)))
);

以下单元测试失败:

        it('test', () => {
            const e1 = hot(       '--1^---2----3-|');
            const e2 = hot(       '-a-^-b-----c--|');
            const expected = cold(   '----x----y-|', {
                x: ['2', 'b'],
                y: ['3', 'c']
            });

            const result = e1.pipe(
                concatMap(x => of(x).pipe(
                    withLatestFrom(e2))
                )
            );

            // but this works:
            // const result = e1.pipe(withLatestFrom(e2));

            expect(result).toBeObservable(expected);
        });

为了通过这个单元测试,应该如何编写弹珠?我做错了什么?我希望通过concatMap在链中(之前withLatestFrom)插入运算符,我还必须以某种方式在弹珠中“标记”它。

4

1 回答 1

1

在你的真实例子中

e1.pipe(
  concatMap(x => of(x).pipe(withLatestFrom(e2)))
);

一切正常,可能是因为是 aBehaviorSubject或 a ReplaySubject,但在您的测试中并非如此。

尽管您使用的是hot( '-a-^-b-----c--|');,但这并不意味着您使用的是BehaviorSubject. 如果我们查看实现,我们会看到它HotObservable扩展了Subject类:

export class HotObservable<T> extends Subject<T> implements SubscriptionLoggable { /* ... */ }

这应该有助于理解为什么会这样:

const result = e1.pipe(withLatestFrom(e2));

这不会:

const result = e1.pipe(
    concatMap(x => of(x).pipe(
        withLatestFrom(e2))
    )
);

在第一个片段中,e2订阅时e1订阅。在第二个中,因为您正在使用concatMap,所以每次e1发出,withLatestFrom(e2))都会被订阅然后取消订阅,因为complete通知来自of(x).

考虑到这一点,这将是我的方法:

注意:我使用的是提供的内置函数rxjs/testing

it('test', () => {

  // might want to add this in a `beforeEach` function
  let testScheduler = new TestScheduler(
    (actual, expected) => (console.log({actual, expected}),expect(actual).toEqual(expected))
  );

  testScheduler.run(({ hot, expectObservable }) => {
    const e1 = hot(       '--1^---2----3-|');
    const e2src = hot(       '-a-^-b-----c--|');
    const e2 = new BehaviorSubject(undefined);

    const result = e1.pipe(
        concatMap(x => of(x).pipe(
            withLatestFrom(e2))
        )
    );

    const source = merge(
      result,

      e2src.pipe(
        tap(value => e2.next(value)),
        
        // this is important as we're not interesting in `e2src`'s values
        // it's just a way to `feed` the `e2` BehaviorSubject
        ignoreElements()
      )
    );
    
    expectObservable(source).toBe('----x----y-|', {
      x: ['2', 'b'],
      y: ['3', 'c']
    });
  });
})
于 2020-08-23T09:27:51.577 回答