阅读更多
测试是完善的研发体系中不可或缺的一环,但是在前端开发的项目中做单一测试的相对较少。为让大家了解前端测试给项目带来的好处,七牛资深前端工程师马逸清结合技术开发团队在前端测试方面的积极探索,特别撰文分享了七牛在前端测试的实践经验。

理想中的代码结构,每个模块都应该比较简单,且每个模块之间的关系也应该非常清晰。但事实上,在做Web开发的过程中,随着功能和迭代次数越来越多,就会产生一些问题。最初,七牛的Web开发并没有写测试,在开发的过程中常遇到代码稍作修改便会产生Bug的情况。而在做一些新功能开发时又很难察觉到它会对旧功能产生影响,到上报之后才发现有问题。另外,代码放久了,也不敢重构。因此,七牛开始考虑做前端测试。

七牛前端测试的早期尝试

七牛最早的尝试是使用 Selenium + Phantom,通过模拟用户操作来进行测试。比如,登录过程的代码大致如下:



测试过程就是打开某个页面之后,输入用户名、密码,点击这个按钮模拟用户的操作过程。这部分的工作其实是在做端到端的测试,而实际项目中,业务逻辑相对复杂,编写端到端测试工作量比较大,测试代码也会很复杂。因此,这样的做法没有很好地发扬起来。

既然做完整测试比较麻烦,七牛前端团队决定做一些更小粒度的测试,对一些基础函数编写单元测试。他们会抽取一些基本函数和组件放在统一的模块中,编写单元测试去验证函数是否符合预期。测试粒度变小以后,相比端到端测试,写测试变得更加容易,但对于 DOM 依赖比较强的部分,就会难以测试。

举个例子,设置七牛开发者平台顶部导航和侧边栏导航选中状态的功能是通过 jQuery 扩展的方式实现的,主要通过匹配URL和导航栏 A标签中href 属性来判断是否应该选中。这里的各种子页面 URL设计比较杂乱,非常容易出错,所以在编写测试的时候,需要把 DOM 结构写进测试脚本。由于一些历史遗留问题,七牛的导航栏有着两种结构,因此,这一部分的测试变得非常痛苦,DOM 结构发生一些微小的变化,整个测试脚本都要跟着改。所以对于依赖 DOM 结构的功能测试还比较少,并没有做到完全覆盖。

在实际开发中要尽量避免逻辑和 DOM 的耦合,分离之后才能更加方便地去验证业务逻辑。使用 MVC 框架是一个比较好的方式,关注度分离,让 DOM 和业务逻辑解耦。

七牛新的项目选择了 AngularJS,AngularJS对测试很友好,不允许在 Controller 里操作 DOM和依赖注入都让测试工作更加方便。换了AngularJS之后,测试的部分主要分为三类:一是Utils,包括一些格式化的函数、验证的函数;二是 Service 里的 Model 状态;三是 View 状态,这些和具体展现以及业务逻辑都有关,是比较复杂的部分。

Utils的测试



以上是对于Utils测试的代码,在代码里注入相关模块就可以进行测试(网上有很多相关的教程,对于 Utils 的测试比较简单)。接下来是做Service的测试,在这个过程中需要做一下设置。如下图所示:



Service封装了很多HTTP请求,这样会依赖于API服务,为此,我们使用AngularJS自带的Mock模块将HTTP这一层处理掉,使用Mock模块在测试时不会发出HTTP请求。同时也可以通过这个模块验证发出的请求以及请求的参数等。再接下来是Controller的测试,主要测一些外围的函数和变量的状态。如以下代码:






在实际的测试过程中,团队会遇到一些依赖不好处理的情况,比如依赖当前时间或者随机字符串,使用 Stub 就可以比较好的处理这种情况。如用户登录后会记录登录的时间,每次请求都会先用当前时间和登录时间进行比较,判断登录是否过期,这里就会依赖当前时间,由于每次运行测试脚本的时间不确定,因此需要替换掉当前时间。七牛使用的是sinon.js,把某个对象当中的某个方法替换掉,一旦每次调用当前时间,它就变成一个固定的值,后面的测试就跟以前的基本方式一样。具体方法如下:



在做测试的时候,某些逻辑代码依赖的是外部的返回值,这时用Stub最合适。因为Stub在Sinon库里可以选择每一次调用的返回值,或者某个参数的返回值,这样能满足绝大部分需求。

Mock除了关注外部依赖的返回值外,还关注外部调用的值。因此,在存/写一些状态的时候,没有返回值就不知道存/写是否成功,只能测试是否调用到了外部依赖的某个方法,传进去的参数是否是预期的。使用Mock的方式,最开始调用时要验证某个Mock对象的某个行为,最后再由Mock对象去验证它的行为是否正确。手工写一个Mock的对象会很麻烦,一般会使用通用的一些函数库来减少工作量。

在测试过程中,大部分情况下用Stub就足够了。如果一些测试依赖某些返回值,但又没有返回值,该怎么办?这里可以用Spy对象去验证一些函数是否被调用、调用时的参数等,Spy就是带有行为验证的Stub。

有了MVC框架和Stub,基本上单元测试中的问题就都能解决了,但是实践中还存在对于Mock Data处理的小问题。七牛团队最初的做法是直接在测试里硬编码了Mock数据,但测试脚本多了以后难以维护,后来便更换了方式,使用了Karma-fixture插件。由于前后端的同时进行,开发时后端API往往没有准备好,所以这里会先构造一些Mock数据,以Json文件的形式放在Mock目录下,再运行一个静态Server专门提供这些Mock数据。使用这样的插件,在测试代码里面便可以把这些Mock数据加载进来直接使用。这样做的好处在于,大家在开发调试和写单元测试时,使用的是同样一套Mock数据。将来如果结构发生一些小的调整(比如加字段),也只需要做简单的修改。

目前用到的工具:Karma+PhantomJS

在七牛早期项目中,测试工具主要使用Selenium,但Selenium配置比较复杂。因此,七牛在新项目开始使用Karma+PhantomJS,Karma比Selenium更加轻量,更适合运行单元测试。而脚本运行的浏览器环境选择PhantomJS,可以直接在命令行里看到结果,不会每次运行测试时弹出界面。测试框架官方推荐Jasmine(包括Stub、Spy的功能),虽然Jasmine的断言以及 Stub功能不如Mocha+Chai+Sinon强大,但对于实际项目已经足够。此外,测试还会依赖一些Karma插件,如测试覆盖率Karma-coverage工具、Karman-fixture工具及Karma-coffee处理工具。此外,前端社区里提供里比较丰富的插件,常见的测试需求都能涵盖到。






工具的配置可按照以上两图的代码先把Karma的文件配置好,然后再配置到自己的gulpfile里。配置gulp如下:



GULP主要配置了两个地方,一是只跑一次测试的testOnce,二是测试代码的testAndWatch。每次进行修改、保存,它都能自动的再跑,这样可以一边开发一边跑测试,从而查看对当前的代码有没有影响。

有了这部分的测试环境,可以把它配置到持续集成的环境当中。由于现有的工具已经非常成熟,这里可以导出覆盖率报告进行分析,之后还可以改进mockData。如果将来业务变得更加复杂,可以考虑加入UI的自动化测试。

前端测试带来的益处

首先,写测试代码和写业务代码时思考方式不一样,写测试代码的时候会考虑业务逻辑的边际条件是什么,这样就能提前找到开发时不太容易找到的Bug。当思路还在功能上时,去修改这个Bug会相对比较轻松,如果后面发现再去修改,就会花更多的工夫。

另一个好处是在写业务代码的时候,理解会更深刻。写测试时会发现代码不好测,输入输出不合理的情况。写测试可以帮助你找到更合理的代码结构。另外,如果很多人共同维护一份代码又需要对公共组件做一些小修改的时候,有了测试改起来会非常安心,测试覆盖比较好的情况下,会减少修改代码的心理负担。

前端的框架非常多,大家可以自由选择适合自己业务的框架。现阶段,前端MVC框架发展非常迅猛,它把DOM的结构和业务累计分离开来,使得测试比以前更好做。此外,Node.js的发展对于后端的测试非常重要,它有一些完善的工具链,在测试方面不会遇到阻碍,因为搭建一个测试环境已经变得非常简单。有了以上的测试环境,在写测试的过程中,更多的便是一个理想和现实之间的平衡。

关于前端测试的建议

对于一些规模较小、人手不足的公司,开发人员写测试的总会遇到一些影响因素,如:
  • 迭代速度快;
  • 业务需求不稳定,有时手里的代码还未写完,又需要修改功能;
  • 人手不足,把功能代码写完已经需要加班,但还需要写测试代码;
大部分的实际情况比解决方案要复杂。在测试的时候,可能要模拟多种实际情况,而业务代码则有可能就是实际的解决方案。对于比较大型的产品,测试代码比业务代码更多,项目紧张或者功能需求不稳定的情况下,过度测试不不可取。

目前七牛的做法是有选择性的写测试。首先,七牛会测试比较重要的部分,评估一些风险。比如数据统计、计费等和用户密切相关的内容。其次是测试比较稳定的部分,即跟业务不相关的部分函数。再次是测试依赖比较少的部分,这里只需要关注它整个逻辑本身。

在人手不足、时间有限的情况下,可能无法很快加上测试环节,这时一定要养成验证的习惯。随着公司业务发展,项目逐渐变大的时候,为了保持代码的可维护性,进行测试变得非常有必要,特别是在开发过程中,它能帮助你找到一些不容易察觉的小Bug。一些开发人员可能认为写测试会耗费额外的时间,但是对于大型软件项目,合适的测试方案能够大大减少今后的维护成本,从长远来看,写测试所花的时间是非常值得的。(责编:陈秋歌)

作者:马逸清,七牛云存储资深前端工程师,上海谷歌开发者社区组织者。关注各种前端技术,也对代码设计和质量维护相关的话题感兴趣,喜爱参加技术分享活动。
  • 大小: 135 KB
  • 大小: 136.9 KB
  • 大小: 158.8 KB
  • 大小: 96.2 KB
  • 大小: 144.8 KB
  • 大小: 143.5 KB
  • 大小: 116.4 KB
  • 大小: 161 KB
  • 大小: 93.5 KB
1
1
评论 共 0 条 请登录后发表评论

发表评论

您还没有登录,请您登录后再发表评论

相关推荐

  • 工作中使用到的单词(软件开发)

    【Spring中这两个核心思想」都是一种设计模式(工厂,代理) 代理 51. AOP术语总结 ■2022/01/06 至 2022/01/30之间整理 (纯单词) ■2022/02/01以降 ■2022/02/23 以降整理 spring 学习 官网链接 Spring组件注册...

  • 工作中使用到的单词(软件开发)_2023_0316备份

    【Spring中这两个核心思想」都是一种设计模式(工厂,代理) 代理 51. AOP术语总结 ■2022/01/06 至 2022/01/30之间整理 (纯单词) ■2022/02/01以降 ■2022/02/23 以降整理 spring 学习 官网链接 Spring组件注册...

  • 面试题:面试题归类 已看1

    一、Java基础 1. String类为什么是final的。 答:主要是为了“效率”和“安全性”的缘故。若String允许被继承,由于它的高度被使用率,可能会降低程序的性能,所以String被定义成final。 2. HashMap的源码,实现...

  • CSDN Blog 2005年08月08日 帖子列表:

    http://blog.csdn.net/Article/D/200508/20050808/index.html CSDN Blog 2005年08月08日 帖子列表:成为技术传播者(一):写在前面CommunityServer研究(一) 安装什么是爱情 CSDN 即兴言论(FengYuanMSFT (袁峰 ...

  • webmagic采集CSDN的Java_WebDevelop页面

    项目中使用到了webmagic,采集论坛一类的页面时需要一些特殊的配置。在此记录一下 先来看看我要采集的页面 点击第2页可以看到它的url是http://bbs.csdn.net/forums/Java_WebDevelop?page=2 ...

  • 程序员常用英语大集合 http://bbs.itheima.com/thread-118950-1-1.html (出处: 黑马程序员IT技术论坛)

    干程序员这行实在是离不开英语,干程序员是一项很...首先编程本身就依赖于英语,虽然现在技术的发展,可以使得某些开发工具在变量名和字段名中支持中文,但还未发现能够完全使用中文的编程语句。   这并不代表我们

  • 尚学堂Java面试题整理

    1. super()与this()的区别? - 6 - 2. 作用域public,protected,private,以及不写时的区别?...5. 在JAVA中,如何跳出当前的多重嵌套循环? - 6 - 6. 什么是java序列化,如何实现java序列化?(写一个实例) - 6 - 7...

  • JAVA项目面试常谈问题以及个人开场介绍模板

    JAVA 人力面试常谈问题 汇总(98个) 1. 请你自我介绍一下 回答提示:一般人回答这个问题...企业很重视一个人的礼貌,求职者要尊重考官,在回答每个问题之后都说一句谢谢.。企业喜欢有礼貌的求职者。 2. 你觉得你个性上

  • 栋的月结 | 第二回合(定期更新、动态、架构、云技术、算法、后端、前端、收听/收看、英文、书籍、影视、好歌、新奇)[含泪总结.. 憋泪分享!]

    应用的基础架构:中央处理器+存储+一系列的输入输出设备;可编程性(计算类、I/O类、指令跳转类);开放设计的外部设备支持(电脑的 CPU 非常简洁,只读入和写出数据并对其进行计算。直接用机器指令太累,没人看懂...

  • 鸟哥的LInux私房菜 基础学习篇 第四版 学习笔记

    (3) 利用 ls -l 显示的文件属性中,第一个字段是文件的权限,共有十个位,第一个位是文件类型, 接下来三个为一组共三组,为使用者、群组、其他人的权限,权限有 r,w,x 三种; (4)如果档名之前多一个『. 』,则...

  • 面试题整理 !=!=未看 *****面试题整理最全 有用

    当向HashSet集合中存入一个元素时,HashSet会调用该对象的 hashCode()方法来得到该对象的hashCode值,然后根据该HashCode值决定该对象在HashSet中的存储位置。 值得主要的是,HashSet集合判断两个元素相等的标准是两...

  • java面试题目整理

    目录Java面试题整理... - 6 -Java面向对象... - 6 -1. super()与this()的区别?... - 6 -2. 作用域public,protected,private,以及不写时的区别?... - 6 -3.......... 在JAVA中,如何跳出当前的多重...

  • 高负载高并发网站架构分析

    由于自己正在做一个高性能大用户量的论坛程序,对高性能高并发服务器架构比较感兴趣,于是在网上收集了不少这方面的资料和大家分享。希望能和大家交流 msn: defender_ios@hotmail.com ————————————...

  • 2020-09-05

    一、Java 基础部分 二、Java 代码查错 三、算法与编程 四、html&JavaScript&ajax 部分 五、Java web 部分 六、数据库部分 七、XML 部分 八、流行的框架与新技术 九、软件工程与设计模式 十、j2ee ...

  • 栋的周评 | 第六回合(定期更新、动态、架构、云技术、算法、后端、前端、收听/收看、英文、书籍、影视、好歌、新奇)

    信封加密:通过数据密钥加密的纯文本数据、使用密钥加密密钥(KEK)来对数据密钥加密、KEK 可被另一个 KEK 加密,但最终会有一个主的密钥(特指 KMS CMK)以加密一个或多个密钥;KMS API 行为:加密、解密。 评分 ...

  • 电机控制领域Harnefors观测器的Matlab仿真模型及其在PMSM无感控制中的高效应用

    内容概要:本文详细介绍了Harnefors观测器在永磁同步电机(PMSM)无感控制中的应用,特别是其在Matlab 2020b环境下的仿真模型。Harnefors观测器以其简洁的十行核心代码实现了对电机角度的精确估算,仅需调整单一参数lambda即可应对各种工况。文中展示了该观测器在初始角度误差极大情况下的优异收敛性能,以及在带载启动和多种速度指令下的稳定性。此外,模型中引入的有效磁链概念使得同一观测器能够兼容表贴式和内嵌式电机,进一步提升了其实用性和灵活性。仿真结果显示,该观测器不仅能在极端条件下迅速收敛,还能在不同电机参数下保持稳定的性能表现。 适合人群:从事电机控制系统设计与开发的技术人员,尤其是关注无感FOC技术和观测器优化的研究人员。 使用场景及目标:①用于研究和开发高性能无感FOC系统;②评估和改进现有电机控制系统的观测器设计;③为初学者提供一个简洁而高效的观测器实现案例,帮助理解和掌握相关技术。 其他说明:文章提供了详细的代码片段和实验数据,便于读者进行复现和进一步探索。同时,强调了模型的扩展性和实用性,特别是在不同类型的永磁同步电机中的应用。

  • COMSOL相场法在水力压裂模拟中的应用:从单一裂缝到复杂多簇裂缝的数值实现

    内容概要:本文详细介绍了使用COMSOL软件中的相场法进行水力压裂模拟的技术细节。首先探讨了单一裂缝的扩展机制,包括相场参数的选择如界面厚度参数(epsilon)、断裂能(Gc),以及各向异性分散设置的影响。接着逐步深入到多个裂缝簇的竞争扩展,特别是两簇和三簇裂缝之间的应力阴影效应及其对裂缝形态的影响。文中还讨论了水力裂缝与天然裂缝相交时的特殊处理方法,如接触条件设定、摩擦系数调整等。此外,文章强调了网格划分、时间步长设置等数值模拟的关键技巧,并展示了如何利用相场变量的动态可视化来直观地观察裂缝的生长过程。 适合人群:从事石油工程、地质力学、计算力学等领域研究的专业人士和技术人员。 使用场景及目标:适用于希望深入了解水力压裂过程中裂缝形成机理的研究人员,以及希望通过数值模拟优化压裂作业的设计工程师。主要目标是掌握相场法的基本原理及其在COMSOL平台上的具体实现方式,从而更好地理解和预测实际工程中的裂缝行为。 其他说明:文章不仅提供了详细的MATLAB代码片段用于指导具体的建模步骤,还分享了许多实用的经验和技巧,帮助读者规避常见的数值发散等问题。同时,通过对不同工况的对比分析,揭示了相场法在处理复杂裂缝网络方面的优势。

  • 管道清污机器人sw16可编辑_三维3D设计图纸_包括零件图_机械3D图可修改打包下载_三维3D设计图纸_包括零件图_机械3D图可修改打包下载.zip

    管道清污机器人sw16可编辑_三维3D设计图纸_包括零件图_机械3D图可修改打包下载_三维3D设计图纸_包括零件图_机械3D图可修改打包下载.zip

  • keras-3.3.2.tar.gz

    该资源为keras-3.3.2.tar.gz,欢迎下载使用哦!

  • C语言课程设计的一些经典项目以及源码.zip

    C语言课程设计的一些经典项目以及源码.zip

Global site tag (gtag.js) - Google Analytics