首页 > 解决方案 > RXJS 大理石测试

问题描述

我对 mergemap 进行了测试,但它没有返回正确的预期结果。有人能帮我吗?

谢谢!

it("should maps to inner observable and flattens", () => {
      const values = { a: "hello", b: "world", x: "hello world" };
      const obs1 = cold(    "-a---a|", values);
      const obs2 = cold(    "-b-b-b-|", values);
      const expected = cold("--x-xxxx-x-|", values);

      const result = obs1.pipe(mergeMap(x => obs2.pipe(map(y => x + " " + y))));
      expect(result).toBeObservable(expected);

标签: rxjsjasmine-marbles

解决方案


我将尝试分解您的测试,以便您了解发生了什么以及您做错了什么。真的很抱歉,但我不会使用jasmine-marbles库,而是编写测试的首选方式(我还建议您避免使用 jasmine-marbles 库)。

当转换为普通的旧弹珠(不使用 jasmine-marbles 库)时,您的测试如下所示:

import { mergeMap, map } from 'rxjs/operators';
import { TestScheduler } from 'rxjs/testing';

describe('mergeMap', () => {
  let testScheduler: TestScheduler;

  beforeEach(() => {
    testScheduler = new TestScheduler(someMatcher);
  });

  it('should maps to inner observable and flattens', () => {
    testScheduler.run(({ cold, expectObservable }) => {
      const values = { a: 'hello', b: 'world', x: 'hello world' };
      const obs1 = cold('-a---a|     ', values);
      const obs2 = cold('-b-b-b-|    ', values);
      const expected = ' --x-xxxx-x-|';

      const result = obs1.pipe(mergeMap(x => obs2.pipe(map(y => x + ' ' + y))));
      expectObservable(result).toBe(expected, values);
    });
  });
});

而这个测试失败了。原因如下:您希望您的测试在第 2、4、5、6、7、9 帧发射,并在第 11 帧完成发射。但是,实际发射发生在第 2、4、6、6、8 帧, 10 帧和第 12 帧完整。现在,为了能够直观地理解为什么以及如何发生这种情况,我将编写一个带有几个评论的测试,我将以不同的方式对齐它们,以便您更好地填充发生的事情:

const obs1 = cold('-a---a|      ', values);
const obs2 = cold(' -b-b-b-|    ', values);
//                      -b-b-b-|
const expected = ' --x-xxxx-x-| ';
// frames:         0123456789012

基本上,在 中mergeMap,您将返回obs2源 observable 何时发出的实例。在这种情况下,源是obs1。当它在第1amergeMap发出第一个值(obs2obs2aobs2

类似地,当obs1发出第二个值时,在第 5 帧,发生另一个订阅,obs2并且由于obs2cold可观察的,另一个生产者被实例化,因此另一个流开始流动。这就是为什么我添加了一条评论来指示第二次订阅何时obs2发生。它从第 5 帧开始,就在第二帧aobs1. 同样,来自第二个订阅的排放obs2是到达消费者的排放。

因此,结合这一点,我们得出了预期帧应该在哪里的结论:

 -b-b-b-|      emits at frames: 2, 4 and 6 and a complete at frame 8
     -b-b-b-|  emits at frames: 6, 8 and 10 and a complete at frame 12
0123456789012

基于此,最终的发射发生在第 2、4、6、6、8 和 10 帧,而完整的发射发生在第 12 帧。这种设置的问题是不可能显示在两个或更多排放量在同一框架内。

也就是说,第 8 帧的发射与第 6 帧的两个发射太接近了。原因是在同一帧发生的发射()在大理石图中用括号分组,而括号在某种程度上隐藏了一些发射。这是你的情况:

 -b-b-b-|    
     -b-b-b-|
--x-x-(xx)x-| // brackets start at frame 6 and represent grouped emissions which all happen at frame 6
0123456666012 // the frames 7, 8 and 9 are "hidden"

第 7、8 和 9 帧是隐藏的,无法表示,因此这些帧的排放量无论如何都无法显示在大理石图中。而且,由于第 8 帧的发射丢失了,因此您无法为该预期发射创建适当的大理石图。

为了使该测试通过,您可以在第6 帧进一步aobs1一帧发出第二个。现在,您的测试可能如下所示(它现在应该通过):

testScheduler.run(({ cold, expectObservable }) => {
  const values = { a: 'hello', b: 'world', x: 'hello world' };
  const obs1 = cold('-a----a|      ', values);
  const obs2 = cold(' -b-b-b-|     ', values);
  //                       -b-b-b-|
  const expected = ' --x-x-xx-x-x-|';

  const result = obs1.pipe(mergeMap(x => obs2.pipe(map(y => x + ' ' + y))));
  expectObservable(result).toBe(expected, values);
});

推荐阅读