罗里吧嗦的一些解释

RxJS使用的越来越多,但发现很多开发者都是使用最基础的部分用来处理http请求,其实RxJS可以做的事情不仅仅是在对网络资源处理过程中替代Promise,但如果按照一些已有的网络博客和分享来看,对二者在实践上的差异确实体现的不明显,所以想从测试的角度,和大家一起理解RxJS,发现它更大的威力。

另外其实本人实际上是在网络上自己学习过一些RxJS的基本概念和使用,并在项目上小小尝试过RxJS,只是觉得尝试的不够彻底,建议看这篇文章的时候最好还是对RxJS的基本概念有一个大的了解。

此文作为对RxJS有了大概了解后,从另一个观察角度去了解RxJS的一个分享。

测试,什么样的测试?

接触过测试的人可能马上会想知道,你说的是什么测试?在测试金字塔的哪一层?可以TDD吗?和我们之前了解的测试有什么特别不一样的?

我说的测试叫弹珠测试(Marble Tests),它属于底层的单元测试级别,主要用于针对自定义操作符的测试,可以TDD,比较特别的算是它是基于DSL的,你必须了解它的DSL之后才能开始写测试。

关于如何写弹珠测试,在官方github上面也有一些文档可以参考,但不是特别详细,没法像一个框架的quick start帮助大家起步。我会尝试和大家一起动手来写这些测试(从最基本的环境搭建开始),不会步步到位,但是关键步骤都有。

看第一个测试?

以下是官网随便找的一个测试,一个简单的map你可以记住你看完这个测试的感受。

  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可以理解为编写弹珠测试的时候使用的一种特定的语言,是基于弹珠测试的上下文可以让机器懂得你语义的一种语言。

我们需要简单介绍下弹珠测试所使用的DSL中的一些基本知识(此部分信息摘自cn.rx.js.org)

首先弹珠语法是用字符串表示随“时间”流逝而发生的事件。任何弹珠字符串的首字符永远都表示“零帧”。“帧”是有点类似于虚拟毫秒的概念。

基本的弹珠语法

  • "-" 时间: 10“帧”的时间段。
  • "|" 完成: 表示 Observalbe 成功完成。这是 Observable 生产者所发出的 complete() 信号。
  • "#" 错误: 终止 Observable 的错误。 这是 Observable 生产者所发出的 error() 信号。
  • "a" 任意字符: 所有其他字符表示由 Observalbe 生产者所发出的 next() 信号的值。
  • "()" 同步分组: 当多个事件需要在同一帧中同步地发出,用圆括号来将这些事件聚集在一起。你可以以这种形式来聚合值、完成或错误。 起始 ( 的位置决定了值发出的时间。
  • "^" 订阅时间点: (只适用于热的 Observabe) 显示测试 Observable 订阅热的 Observable 的点。它是此 Observable 的“零帧”,在 ^ 前的所有帧都将是无效的。

Subscription 的弹珠语法

  • "-" 时间: 10“帧”的时间段。
  • "^" 订阅时间点: 显示订阅发生的时间点。
  • "!" 取消订阅时间点: 显示取消订阅发生的时间点。

所以我们尝试逐行理解下前面出现的测试

  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);

这个测试的步骤是这样的

  • 创建一个 Observable a,a在第30帧传入1,第60帧传入2,第90帧传入3,第120帧complete。
  • 对a进行map操作的方法r,r将a中的每个值变为原来的10倍
  • 期待对a的进行方法r的操作后,在第30帧收到10,第60帧收到20,第90帧收到30,第120帧结束
  • 期待对a的订阅在第10帧开始,在第120帧结束

自己搭建环境?

刚刚是我们用官网的例子结合一些辅助网站的资料,对弹珠测试进行的简单的了解,下面我们开始自己搭建一个可以自己写弹珠测试、运行测试的环境。

我们先使用和官网一样的第三方依赖创建环境,等我们慢慢熟悉这套之后,再换用其他第三方的依赖搭建环境。
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方法就可以使用啦!

下一篇 Fancy的弹珠图

弹珠测试之所以能称之为弹珠测试,从字面意思上很容易猜测和弹珠图相关。
我们已经有一个基本的测试了,下一篇我们开始把它变成弹珠图吧。

RxJS修炼之 用弹珠测试学习RxJS相关推荐

  1. debounceTime 和 throttleTime 的弹珠图

    debounceTime:测试代码 import {concat,debounceTime,filter,interval,mapTo,of,take,throttleTime, } from 'rx ...

  2. 利用UIDynamicAnimator做弹珠弹跳小游戏

    本来想多了解了解`CMMotionManager`手机的陀螺仪的,并且用陀螺仪做了一个类似于手机的桌面的动态桌面,其实就是用陀螺仪的重力变化将图片位置稍微移动移动即可.后来接触的越多了解的东西越多,毕 ...

  3. ssr怎么编辑服务器ip_“阴阳师”IP影响力有多大?网易用它做了一款弹珠游戏,TapTap评分高达9.8分...

    文|手游那点事|虹彤.Jimmy "阴阳师"IP衍生的想象空间到底有多大? 在今年的"520发布会"上,网易非常大手笔地公布了<阴阳师>IP的一系列 ...

  4. python 乒乓球_python使用pygame实现笑脸乒乓球弹珠球游戏

    今天我们用python和pygame实现一个乒乓球的小游戏,或者叫弹珠球游戏. 笑脸乒乓球游戏功能介绍 乒乓球游戏功能如下: 乒乓球从屏幕上方落下,用鼠标来移动球拍,使其反弹回去,并获得得分,如果没有 ...

  5. 使用Scratch制作项目《弹珠游戏》

    不知道大家有没有听说过这样一句话,"80后玩弹珠,90后玩游戏,00后怎么消遣业余时间?不是王者就是吃鸡." 作为一名90后,我们对打弹珠在熟悉不过了,今天,我们就来了解以下如果使 ...

  6. js实现方块弹珠游戏

    下载地址:https://files.cnblogs.com/files/liumaowu/%E5%BC%B9%E4%B8%80%E5%BC%B9%E6%89%93%E6%96%B9%E5%9D%97 ...

  7. 手工做迷宫_教你利用瓦楞纸手工制作弹珠迷宫

    现在的小孩都迷恋上电脑游戏和手机视频,反而很少机会接触到一些传统的益智玩具.今天的手工制作教程里面51费宝教你如何利用瓦楞纸板做一个可以比赛竞技的DIY弹珠迷宫游戏,你可以通过把握手柄控制迷宫里面的珠 ...

  8. 基于ubuntu16.04部署IBM开源区块链项目-弹珠资产管理(Marbles)

    前言 本教程基本上是对Marbles项目的翻译过程. 如果英文比较好的话,建议根据官方操作说明,一步步进行环境部署.当然你也可以参考本教程在自己的主机上部署该项目. Marbles 介绍 关于 Mar ...

  9. Linux乒乓球游戏,python使用pygame实现笑脸乒乓球弹珠球游戏

    今天我们用python和pygame实现一个乒乓球的小游戏,或者叫弹珠球游戏. 笑脸乒乓球游戏功能介绍 乒乓球游戏功能如下: 乒乓球从屏幕上方落下,用鼠标来移动球拍,使其反弹回去,并获得得分,如果没有 ...

  10. go定时器 每天重复_通过测试学习Go:Hello, World

    点击上方蓝色"Go语言中文网"关注我们,设个星标,每天学习 Go 语言 你可以在这里查看本章的所有代码[1] 按照传统,我们学习新语言编写的第一个程序都是 Hello,world. ...

最新文章

  1. Linux学习(十二)---RPM和YUM
  2. 服务器mysql在哪里_mysql的服务器在哪里
  3. 对quake3源代码的学习与研究初步的计划
  4. Redhat Linux通过RPM安装搭建LAMP环境
  5. 笔试题--Multicore简答题(下)
  6. 低价iPhone 12彻底没戏了?苹果严控渠道:给拼多多等电商供货罚款40万元/台
  7. python可以手眼定标吗_手眼标定 相关实例(示例源码)下载 - 好例子网
  8. $$\int_0^{nh}x(x-h)\cdots (x-nh)dx=h^{n+2}\int_0^nx(x-1)\cdots (x-n)dx$$
  9. 面试AI岗,为什么我在100人中拿到了唯一年薪70万的offer?
  10. CASS11最新版免狗下载安装教程
  11. (TNNLS-2022)步态质量感知网络:面向轮廓步态识别的可解释性
  12. Linux系统 应急响应自动化检测工具 GScan ——使用教程
  13. PAT乙级做题部分总结
  14. 希腊神话传说中的诸神
  15. IAP协议实现苹果home键功能
  16. 【原创干货】免费企业服务评测汇总
  17. 关于html video 在chrome浏览器下无法快进问题解决
  18. 分布式-SOA服务化接口设计
  19. Cesium各类实体的添加
  20. ElasticSearch + Kibana

热门文章

  1. Atiitt 软件设计之道 attilax著 1. 总概念 隶属于软件工程。。 2 2. 需求分析 3 3. 设计分类 3 3.1. 按照力度 总体设计架构设计 概要设计 详细设计 3 3.2.
  2. Atitit.搜索引擎内容来源解决之道
  3. Atitit 软件体系的进化,是否需要一个处理中心
  4. Atitit 项目培训与学校的一些思路总结
  5. Atitit 发帖机实现(4 )- usbQBM1601 gui操作标准化规范与解决方案attilax总结
  6. Atitit.嵌入式web 服务器 java android最佳实践
  7. paip.python ide 总结最佳实践o4.
  8. paip.gui控件form窗体的原理实现以及easyui的新建以及编辑实现
  9. 钉钉机器人:python发送消息-加签模式
  10. CA机构是如何保护自己私钥的?