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

理想中的代码结构,每个模块都应该比较简单,且每个模块之间的关系也应该非常清晰。但事实上,在做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 行为:加密、解密。 评分 ...

  • node-v5.1.1-linux-x64.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

  • 基于Android+Java的 AES 加密算法分析.zip

    Android是一种基于Linux内核(不包含GNU组件)的自由及开放源代码的移动操作系统,主要应用于移动设备,如智能手机和平板电脑。该系统最初由安迪·鲁宾开发,后被Google公司收购并注资,随后与多家硬件制造商、软件开发商及电信营运商共同研发改良。 Android操作系统的特点包括: 开放源代码:Android系统采用开放源代码模式,允许开发者自由访问、修改和定制操作系统,这促进了技术的创新和发展,使得Android系统具有高度的灵活性和可定制性。 多任务处理:Android允许用户同时运行多个应用程序,并且可以轻松地在不同应用程序之间切换,提高了效率和便利性。 丰富的应用生态系统:Android系统拥有庞大的应用程序生态系统,用户可以从Google Play商店或其他第三方应用市场下载和安装各种各样的应用程序,满足各种需求。 可定制性:Android操作系统可以根据用户的个人喜好进行定制,用户可以更改主题、小部件和图标等,以使其界面更符合个人风格和偏好。 多种设备支持:Android操作系统可以运行在多种不同类型的设备上,包括手机、平板电脑、智能电视、汽车导航系统等。 此外,Android系统还有一些常见的问题,如应用崩溃、电池耗电过快、Wi-Fi连接问题、存储空间不足、更新问题等。针对这些问题,用户可以尝试一些基本的解决方法,如清除应用缓存和数据、降低屏幕亮度、关闭没有使用的连接和传感器、限制后台运行的应用、删除不需要的文件和应用等。 随着Android系统的不断发展,其功能和性能也在不断提升。例如,最新的Android版本引入了更多的安全性和隐私保护功能,以及更流畅的用户界面和更强大的性能。此外,Android系统也在不断探索新的应用场景,如智能家居、虚拟现实、人工智能等领域。 总之,Android系统是一种功能强大、灵活可定制、拥有丰富应用生态系统的移动操作系统,在全球范围内拥有广泛的用户基础。

  • Visio卷积神经网络(CNN)结构图模板:专业设计资源下载

    Visio卷积神经网络(CNN)结构图模板是一个专为深度学习和人工智能领域设计的绘图工具。该模板提供了一套完整的预制图形和符号,包括卷积层、池化层、全连接层、激活函数等,使得用户能够快速构建和自定义复杂的神经网络架构。通过这个模板,研究人员和工程师可以更加直观和高效地展示和分享他们的模型设计。它适用于学术论文、技术报告、项目演示等多种场合。该资源还包括易于编辑的图层和格式,允许用户根据需要调整网络的每个部分。此外,Visio的拖放功能和自动化特性大大简化了绘图过程,使得即使是初学者也能轻松创建专业的CNN结构图。

  • 2024-2030中国粉尘环境在线监测报警系统市场现状研究分析与发展前景预测报告.docx

    2024-2030中国粉尘环境在线监测报警系统市场现状研究分析与发展前景预测报告

  • 基于 SpringCloud 和 Vue3 的OA系统源码+数据库.zip

    基于 SpringCloud 和 Vue3 的OA系统源码+数据库.zip 基于 SpringCloud 和 Vue3 的OA系统源码+数据库.zip基于 SpringCloud 和 Vue3 的OA系统源码+数据库.zip基于 SpringCloud 和 Vue3 的OA系统源码+数据库.zip基于 SpringCloud 和 Vue3 的OA系统源码+数据库.zip基于 SpringCloud 和 Vue3 的OA系统源码+数据库.zip基于 SpringCloud 和 Vue3 的OA系统源码+数据库.zip基于 SpringCloud 和 Vue3 的OA系统源码+数据库.zip基于 SpringCloud 和 Vue3 的OA系统源码+数据库.zip基于 SpringCloud 和 Vue3 的OA系统源码+数据库.zip基于 SpringCloud 和 Vue3 的OA系统源码+数据库.zip

Global site tag (gtag.js) - Google Analytics