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方法就可使用啦!
彈珠測試之因此能稱之爲彈珠測試,從字面意思上很容易猜想和彈珠圖相關。咱們已經有一個基本的測試了,下一篇咱們開始把它變成彈珠圖吧。