测试 RxJS 的正确方法

11
我买了一本书叫做《rxjs实战》,刚刚完成了测试部分。
测试rxjs代码不同于普通的测试,因为所有的东西都是惰性加载的。
在这本书中,他们提到了两种测试方法,要么使用通过(我正在使用QUnit和done信号异步代码完成),要么使用弹珠图。
我的问题是,我应该选择上面提到的哪种方法?

你能具体一点吗?什么是大理石图测试?在你的特定情况下,你需要测试哪些方面?这本书难道没有对比两种测试类型的优缺点吗? - AngularChef
弹珠图示(Marble diagrams)[链接](https://github.com/ReactiveX/rxjs/blob/master/doc/writing-marble-tests.md)。这本书并不涵盖优缺点,只介绍了测试rxjs的方式。 - softshipper
有趣的是,我不知道这些。 - AngularChef
2个回答

12

时间已经过去,现在使用TestScheduler自己进行这些大理石测试肯定是可能的(甚至很容易)。它们是一种全面测试发射,错误,完成和订阅的简单易懂格式的绝佳方式。以下是他们的文档中的示例:

import { TestScheduler } from 'rxjs/testing';

const testScheduler = new TestScheduler((actual, expected) => {
  // asserting the two objects are equal
  // e.g. using chai.
  expect(actual).deep.equal(expected);
});

// This test will actually run *synchronously*
it('generate the stream correctly', () => {
  testScheduler.run(helpers => {
    const { cold, expectObservable, expectSubscriptions } = helpers;
    const e1 =  cold('-a--b--c---|');
    const subs =     '^----------!';
    const expected = '-a-----c---|';

    expectObservable(e1.pipe(throttleTime(3, testScheduler))).toBe(expected);
    expectSubscriptions(e1.subscriptions).toBe(subs);
  });
});

如果您使用Jasmine,我写了一个名为marbleTest()的小助手来减少样板文件,可以在@s-libs/ng-dev中使用
import { marbleTest } from "s-ng-dev-utils";

it("generate the stream correctly", marbleTest(helpers => {
  const { cold, expectObservable, expectSubscriptions, testScheduler } = helpers;
  const e1 = cold(" -a--b--c---|");
  const subs = "    ^----------!";
  const expected = "-a-----c---|";

  expectObservable(e1.pipe(throttleTime(3, testScheduler))).toBe(expected);
  expectSubscriptions(e1.subscriptions).toBe(subs);
}));

12

我最近从同事那里频繁听到这个问题。最终我在我的博客上记录了一下如何测试RxJs,点此查看。由于你的问题似乎与RxJs5有关,因此我将在此处引用我文章中相关的部分。

RxJs5中像RxJs4一样进行测试

当您将代码库从RxJs4迁移到5时,您会发现很多东西已经被移动、重命名,而且最重要的是TestScheduler的实现不再可用。 RxJs贡献者kwonoj创建了一个兼容性工具来帮助迁移到RxJs5。您可以使用npm安装它 npm install @kwonoj/rxjs-testscheduler-compat。并非所有的TestScheduler功能都已实现,但最重要的.startScheduler正在工作。

const TestScheduler = require('@kwonoj/rxjs-testscheduler-compat').TestScheduler;
const next = require('@kwonoj/rxjs-testscheduler-compat').next;
const complete = require('@kwonoj/rxjs-testscheduler-compat').complete;

it('works in RxJs5 with the compat package', () => {
  const scheduler = new TestScheduler(); // Note; no longer the Rx.TestScheduler

  const results = scheduler.startScheduler(
    () => Rx.Observable.interval(100, scheduler).take(3),
    { created: 100, subscribed: 200, unsubscribed: 1000 } // NOTE: disposed is now renamed to unsubscribed
  );

  collectionAssert.assertEqual(res.messages, [
    next(200 + 100, 0),
    next(200 + 200, 1),
    next(200 + 300, 2),
    complete(200 + 300)
  ]);
});

使用新的 Marble 测试语法测试 RxJs5

RxJs 团队引入了 Marble 测试语法,更直观地定义您的操作符或自定义代码应该如何运行。

var e1 = hot('----a--^--b-------c--|');
var e2 = hot(  '---d-^--e---------f-----|');
var expected =      '---(be)----c-f-----|';

expectObservable(e1.merge(e2)).toBe(expected);

在撰写本文时,他们尚未使此方法在 RxJs5 库之外真正易于使用。有可供参考的实现,以了解如何自行完成。您也可以在 RxJs5 的代码库 中查看如何设置测试框架以进行自己的 marble 测试。关于使用 RxJs5 进行测试的文档化问题存在一个开放性问题。我尚未成功地设置我的测试框架以使用这种方式进行 marble 测试。


1
听起来,rxjs5目前还无法进行测试。 - softshipper
RxJS 5的测试现状总结得非常好。感谢提供shim的链接 - 在我看来,这是目前唯一真正可行的选择!因此,回应@zero_coding - 有了这个,RxJS 5可以像其他Rx端口一样完全可测试,但没有它就不行。 - LJW
3
@zero_coding 同意。我的印象是,当涉及到单元测试时,RxJS正成为其自身实现复杂性的受害者。测试 promise 很简单,async/await 也是如此,只需要一个简单的 .then(done)。但是 observables 是对几乎所有内容的抽象... 这使得单元测试变得模糊不清... - ducin
这些信息已经过时了。 - Liam

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