在RxJs和Angular中测试可观察对象的“next”回调函数

5

我正在尝试使用RxJs Observables在Angular中进行一个非常简单的测试,但是我无法成功。基本上我要测试的内容如下:

// We're inside some Angular component here...
let testMe = 0;

function somethingOrOther(): void {

    this.someService.methodReturningObservable()
      .subscribe(
          (nextValue: number): void => {
              testMe += nextValue;
          }
      ) 
}

methodReturningObservable发出值时,我如何测试testMe是否正确更新?

我尝试了以下方法:

it(`works 'cuz I want it to`, fakeAsync(() => {
    spyOn(this.someService, 'methodReturningObservable').and.returnValue(cold('a', {a: 10}));

    tick();

    expect(component.testMe).toBe(10);
}));

所以,tick() 在这里似乎没有任何作用。我的 cold 值从未在我的 spy 上发出过信号。

我尝试使用如下链接https://netbasal.com/testing-observables-in-angular-a2dbbfaf5329的marbles部分所示的getTestScheduler.flush()

我能否像这样使用 marbles 来发出 Observable 的值?在 AngularJS 中非常容易,只需触发 digest,但是我似乎无法让 Anguar 在 Observable 的下一个回调函数中让我进入。

1个回答

3
我为您准备了一个简单的 Stackblitz,用于展示如何测试您所描述的简单组件方法。下面是该 Stackblitz 的规范:(链接)
it(`works with "of" 'cuz I want it to`, () => {
    spyOn(someService, 'methodReturningObservable').and.returnValue(of(10));
    component.somethingOrOther();
    expect(component.testMe).toBe(10);
});

我对您的代码进行了一些更改:

  • 我对您的组件方法进行了微小的更改以使其正常工作。在Stackblitz中有详细说明。
  • cold()函数来自mable测试库,但是这对于如此简单的功能来说是过度杀伐了。 rxjs 提供了of Observable创建方法,可以创建一个冷同步可观察对象,可以订阅它(但如果您确实想以这种方式进行测试,请参见下面的更多信息)。
  • 由于上面的规范使用同步可观察对象,因此不需要使用fakeAsync(),因为它会立即完成。
  • 测试的方法需要显式调用才能被测试,上面的代码component.somethingOrOther()已经完成了。

正如您在Stackblitz中所看到的,这个测试非常成功。

现在,如果您想即使针对这个简单的情况也使用mable测试,我在Stackblitz中设置了另一个规范。 它如下所示:

it(`works with "cold" 'cuz I want it to`, () => {
    spyOn(someService, 'methodReturningObservable').and.returnValue(cold('a', { a: 10 }));
    component.somethingOrOther();
    getTestScheduler().flush(); // flush the observables
    expect(component.testMe).toBe(10);
});
  • 请注意需要调用组件函数的事实
  • 还需要执行getTestScheduler的刷新操作。

现在,在Stackblitz中,这两个测试都通过了。

Angular官方文档中关于marble testing的内容可以在这里找到。

希望这可以帮到您。


有几件事情:实际上我是在调用这个方法,只是忘记在原始问题中包含它。我一直在fakeAsyncticktestScheduler.flush()之间感到困惑,并尝试了多种组合。结果发现我还有另一个愚蠢的问题,就是在服务调用之前退出了方法,因为其他变量的原因。所以我的刷新尝试失败了,因为我实际上从未进行过调用。这是一个漫长的一周...谢谢你确认我可以在这种情况下使用marbles,这正是我希望的! - Spencer
有没有一种方法可以在每次发射后使用弹珠和测试?如果我有 cold('--a- b--c'),我如何在每次发射后停止并检查状态? - Spencer
Marble测试的核心在于使用基于文本的弹珠图设置可观察的“输入”和期望的“输出”,然后将实际输出与期望输出进行比较。就像实际的可观察对象一样,在发射之间没有“停止”。如果您有更详细的问题,我鼓励您提出一个新问题。 :) 有关编写Marble测试的详细信息,请参见此处。 - dmcgrandle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接