RxJS使用的愈来愈多,但发现不少开发者都是使用最基础的部分用来处理http请求,其实RxJS能够作的事情不只仅是在对网络资源处理过程当中替代Promise,但若是按照一些已有的网络博客和分享来看,对两者在实践上的差别确实体现的不明显,因此想从测试的角度,和你们一块儿理解RxJS,发现它更大的威力。html
另外其实本人其实是在网络上本身学习过一些RxJS的基本概念和使用,并在项目上小小尝试过RxJS,只是以为尝试的不够完全,建议看这篇文章的时候最好仍是对RxJS的基本概念有一个大的了解。node
此文做为对RxJS有了大概了解后,从另外一个观察角度去了解RxJS的一个分享。git
接触过测试的人可能立刻会想知道,你说的是什么测试?在测试金字塔的哪一层?能够TDD吗?和咱们以前了解的测试有什么特别不同的?github
我说的测试叫弹珠测试(Marble Tests),它属于底层的单元测试级别,主要用于针对自定义操做符的测试,能够TDD,比较特别的算是它是基于DSL的,你必须了解它的DSL以后才能开始写测试。typescript
关于如何写弹珠测试,在官方github上面也有一些文档能够参考,但不是特别详细,无法像一个框架的quick start帮助你们起步。我会尝试和你们一块儿动手来写这些测试(从最基本的环境搭建开始),不会步步到位,可是关键步骤都有。网络
如下是官网随便找的一个测试,一个简单的map你能够记住你看完这个测试的感觉。app
asDiagram('map(x => 10 * x)')('should map multiple values', function () { var a = cold('--1--2--3--|'); var asubs = '^ !'; var expected = '--x--y--z--|'; var r = a.map(function (x) { return 10 * x; }); expectObservable(r).toBe(expected, { x: 10, y: 20, z: 30 }); expectSubscriptions(a.subscriptions).toBe(asubs); });
我并不知道你的感觉,我第一眼是有点懵的反正,缘由也很简单为何出现 | ^ - 这些字符,它们在这里是干什么的? 这个时候要放出DSL这个大招了。框架
前面咱们随意找的一个测试,彷佛并不符合测试语义化这一点,实际上是由于咱们没有理解它所使用的DSL,此处的DSL能够理解为编写弹珠测试的时候使用的一种特定的语言,是基于弹珠测试的上下文可让机器懂得你语义的一种语言。单元测试
咱们须要简单介绍下弹珠测试所使用的DSL中的一些基本知识(此部分信息摘自cn.rx.js.org)学习
首先弹珠语法是用字符串表示随“时间”流逝而发生的事件。任何弹珠字符串的首字符永远都表示“零帧”。“帧”是有点相似于虚拟毫秒的概念。
基本的弹珠语法
Subscription 的弹珠语法
因此咱们尝试逐行理解下前面出现的测试
asDiagram('map(x => 10 * x)')('should map multiple values', function () { *** });
asDiagram是指基于测试生成 PNG 弹珠图,生成弹珠图的原理是根据一些结构化的信息,加上一些如imagemagick的库,就能够生成以下的图了,更多的操做符对应的弹珠图例子能够再rxmarbles.com找到。
var a = cold('--1--2--3--|'); var asubs = '^ !'; var expected = '--x--y--z--|'; var r = a.map(function (x) { return 10 * x; }); expectObservable(r).toBe(expected, { x: 10, y: 20, z: 30 }); expectSubscriptions(a.subscriptions).toBe(asubs);
这个测试的步骤是这样的
刚刚是咱们用官网的例子结合一些辅助网站的资料,对弹珠测试进行的简单的了解,下面咱们开始本身搭建一个能够本身写弹珠测试、运行测试的环境。
咱们先使用和官网同样的第三方依赖建立环境,等咱们慢慢熟悉这套以后,再换用其余第三方的依赖搭建环境。
ready go!
首先咱们建立一个ts项目(最近ts写多了),并使用yarn安装基本的测试依赖。
"dependencies": { "@types/chai": "^4.0.10", "@types/mocha": "^2.2.45", "chai": "^4.1.2", "mocha": "^4.0.1", "rxjs": "^5.5.6", "ts-node": "^4.1.0", "typescript": "^2.6.2" }, "scripts": { "test": "TS_NODE_FAST=true mocha --compilers ts:ts-node/register --opts spec/support/coverage.opts \"specs/**/*.spec.ts\"" }
而后我依样画瓢的把对TestScheduler的包装方法copy了下,中间遇到一些写法不同的部分稍做调整。
import { TestScheduler, Observable } from 'rxjs'; import { SubscriptionLog } from 'rxjs/src/testing/SubscriptionLog'; import { ColdObservable } from 'rxjs/src/testing/ColdObservable'; import { HotObservable } from 'rxjs/src/testing/HotObservable'; export type observableToBeFn = (marbles: string, values?: any, errorValue?: any) => void; export type subscriptionLogsToBeFn = (marbles: string | string[]) => void; const testScheduler = new TestScheduler(null); export function hot(marbles: string, values?: any, error?: any): HotObservable<any> { return testScheduler.createHotObservable.apply(testScheduler, arguments); } export function cold(marbles: string, values?: any, error?: any): ColdObservable<any> { return testScheduler.createColdObservable.apply(testScheduler, arguments); } export function expectObservable(observable: Observable<any>, unsubscriptionMarbles: string = null): ({ toBe:observableToBeFn }) { return testScheduler.expectObservable.apply(testScheduler, arguments); } export function expectSubscriptions(actualSubscriptionLogs: SubscriptionLog[]): ({ toBe: subscriptionLogsToBeFn }) { return testScheduler.expectSubscriptions.apply(testScheduler, arguments); } export function time(marbles: string): number { return testScheduler.createTime.apply(testScheduler, arguments); }
这样基本的hot cold方法就可使用啦!
弹珠测试之因此能称之为弹珠测试,从字面意思上很容易猜想和弹珠图相关。咱们已经有一个基本的测试了,下一篇咱们开始把它变成弹珠图吧。