🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] # 持续集成和前端自动化测试 ​ 持续集成是互联网软件开发上线流程中的核心一环,自动化测试是持续集成得以实现的核心步骤,缺乏了自动化测试,持续集成自然无从谈起。 ​ 在日常的开发中,前端错综复杂的变化引发的 bug 往往令开发者头疼,或多或少经历过 修完东墙西墙倒 的经历,此时前端自动化测试就显得非常重要。 ​ 前端的自动化测试无非也是编写测试用例,在持续集成时执行跑通全部测试用例。如果是一个短平快的小项目,引入前端自动化测试,编写测试用例,无疑只会增加开发成本,然而当项目扩大、迭代频繁、逻辑复杂、需求反复变更的情况下,回归测试的成本是巨额的,自动化测试的优势就能体现出来。 > 自动化测试的收益 = 迭代次数 \* 全手动执行成本 - 首次自动化成本 - 维护次数 \* 维护成本 ​ 尽早引入前端自动化测试不仅能够减少项目 bug 出现概率 (尤其是回归测试中的 bug),还能更好地进行代码组织,增强项目的可维护性,尤其对于工程质量较差的项目,收益是巨大的;如果将其应用于持续集成中,commit 触发自动执行测试脚本,还能大幅提升团队的开发效率。 # 自动化测试的必要性 好处很多,包括减少错误、提高效率等,尤其是前端项目越来越庞大且多人维护时,前端自动化测试就会显得尤其重要。 代价也有,毕竟需要额外的学习成本。但在你的项目中加入测试,也许没你想象的那么困难。 # [JavaScript 测试︰ 单元 vs 功能 vs 集成测试](http://wildflame.me/javascript-testing-unit-functional-integration/) 大多数应用程序都需要 单元测试 和 功能测试,而许多复杂的应用程序在此基础上,还需要 集成测试。 1. **单元测试** 测试单个函数或者类,提供输入,确保输出和预期的一样。单元测试的粒度要尽可能小,不要考虑其他类和模块的实现。用来确保每个组件正常工作 —— 测试组件的 API 。在面向对象的语言中,单元可以从单一方法到整个类。 2. **集成测试** 测试整个流程或者某组件能够按预期的运行,用来覆盖跨模块的过程。同时也要包括一些反面用例,用来确保不同组件互相合作 —— 测试组件的 API, UI, 或者边缘情况(比如数据库I/O,登陆等等)。 3. **功能测试** 站在产品的角度测试各个场景,通过操作浏览器或者网站,忽略内部实现细节和结构,确保和预期的行为一样。—— UI 界面功能测试 你应该把 单元,集成 和 功能测试 互相隔离开来,这样你就可以在开发时分别的运行它们。在持续的集成过程中,测试一般会出现在下面三个阶段。 1. 开发阶段,主要是程序员反馈。这时单元测试很有用。 2. 中间阶段,主要是能够在发现问题时立刻停下来。这时各种测试都很有用。 3. 生产环境,主要是运行功能测试套件中一个叫做「冒烟测试」的子集,确保部署的时候没有弄坏什么东西。 如果你问我该使用那个测试?**所有的**。 **在前端测试金字塔中,大部分测试都是单元测试。** # BDD vs TDD 主流的测试类型,如何选择测试的策略。 ## TDD (Test-Driven Development) 测试驱动开发 ​ TDD 顾名思义,开发者根据需求先编写测试用例,再逐步开发,最终满足全部测试用例的需求。 ​ TDD 的基本思路就是通过测试来推动整个开发的进行,但测试驱动开发并不只是单纯的测试工作,而是把需求分析,设计,质量控制量化的过程。 ​ TDD 的重要目的不仅仅是测试软件,测试工作保证代码质量仅仅是其中一部分,而且是在开发过程中帮助客户和程序员去除模棱两可的需求。TDD 首先考虑使用需求(对象、功能、过程、接口等),主要是编写测试用例框架对功能的过程和接口进行设计,而测试框架可以持续进行验证。 ​ 刚开始的时候,只有测试用例,未进行功能开发,执行测试用例,满屏是红色的测试用例不通过提示,随着测试用例被满足变绿,最终全部变绿,功能开发完成,因此前端自动化测试也被叫做 Red-Green Development。 > TDD 先写测试再写代码,单位是模块,多用于 单元测试 > 重点在测试代码,属于 白盒测试 > 测试内容是模块,速度快,但是忽略模块间依赖,安全感低 > > ​ 流程 > 1. 编写测试用例 > 2. 运行测试,测试用例无法通过测试 > 3. 编写代码,时测试用例通过测试 > 4. 优化代码,完成开发 > 5. 重复上述步骤 > > ​ 优势 > 1. 长期减少回归 bug > 2. 代码质量更好(组织,可维护性) > 3. 测试覆盖率高 > 4. 错误测试代码不容易出现 ## BDD (Behavior Driven Development) 行为驱动开发 ​ 测试用例模拟用户的操作行为,通常在完成业务代码开发之后,以用户的操作为指导编写测试代码。当测试用例跑通之后,就可以认为系统的整体流程已经流畅。 BDD 的模式适用于平时的业务代码开发,因为业务的需求有可能变更频繁,但操作流程有可能不会变化,当业务代码发生变化的时候,可以使用原来的测试用例继续跑代码,节省了开发时间。 BDD 先写代码再写测试,测试单位是功能,多用于集成测试 重点在测试 UI(DOM)功能,属于黑盒测试 测试内容是整套操作流程,速度慢,往往需要多个模块配合,安全感高 > TDD 开发模式更适用于开发,类似方法函数库,对于数据的处理,对于这种显示组件,更加推荐于 BDD 的开发方式,这样既有了测试,也不会增加过多的工作负担, > > 在平时的项目中,通常使用 TDD 和 BDD 相结合来进行测试,TDD 负责方法类、独立组件的测试。BDD 则负责整体业务模块的测试。 一般的 TDD 的开发流程为: 1. 编写测试 (一个会失败的 case) 2. 运行测试,并看到这个测试失败 3. 编写代码 (足够让测试通过的代码) 4. 运行测试,并看到测试通过 5. 重构 6. 运行测试,并看到测试通过 然后**如此循环**,而在前端开发中,很长一段时间,这个流程受限于开发环境,比如添加了一个新的 JavaScript 源文件,开发者需要在 HTML 中引入相应地文件,以及响应的测试文件,然后刷新页面 (有时候还需要清空浏览器缓存)。 在这个过程中,开发者真正关注的就是编写测试,运行测试,编写实现,重构等等,需要不断的重复这个过程。而不是关注如刷新页面,清空缓存,修改 HTML 对脚本的引用等武馆的工作。 参考: * [前端自动化测试jest_萌萌哒的瑞萌萌的博客](https://blog.csdn.net/weixin_46232841/article/details/117528453) * [TDD 与 BDD 仅仅是语言描述上的区别么? - 知乎](https://www.zhihu.com/question/20161970) * [从Unit Test到TDD再到BDD](https://www.jianshu.com/p/07f5ea4761ad) * [虚拟座谈会:代码测试比率、测试驱动开发及行为驱动开发](http://www.infoq.com/cn/articles/virtual-panel-tdd-bdd) ## 断言库 Chai 断言库(assertion library)是用来写断言的库。 维基百科的 [断言(程序)](https://zh.wikipedia.org/wiki/%E6%96%B7%E8%A8%80_(%E7%A8%8B%E5%BC%8F))一文是这么解释断言的:在[程序设计](https://zh.wikipedia.org/wiki/%E7%A8%8B%E5%BC%8F%E8%A8%AD%E8%A8%88)中,**断言**(**assertion**)是一种放在程序中的[一阶逻辑](https://zh.wikipedia.org/wiki/%E4%B8%80%E9%9A%8E%E9%82%8F%E8%BC%AF)(如一个结果为真或是假的逻辑判断式),目的是为了标示与验证程序开发者预期的结果-当程序运行到断言的位置时,对应的断言应该为真。若断言不为真时,程序会中止运行,并给出错误消息。 根据风格,断言库又区分为 TDD 风格 和 BDD 风格。[Chai](http://chaijs.com/) 便是其中一个著名的代表,它同时支持这两种风格。 # 前端测试金字塔 前端测试金字塔是一个前端测试套件应该如何构建的结构化表示。 理想的测试套件由单元测试,一些快照测试和一些端到端(e2e)测试组成。 ![](https://box.kancloud.cn/06001c162f34e2a232bd29a58f17e901_321x242.png) 这是测试金字塔的改进版本,特定于测试前端应用程序。 # 前端测试框架 在大型项目或迭代频繁的项目中,单元测试还是很必要的,当前单元测试框架很多,功能各不相同。使用测试框架的好处是可以让我们写测试更方便,比如有测试结果报告,还有一些 helper function 来帮助我们更好的编写和组织测试代码,比如`expect(counter.number).to.be.equal(0)`就是测试框架提供的很容易理解的代码。 ![热门的 JavaScript 自动化单元测试框架](https://box.kancloud.cn/d757cf9ad6183c08a10df8a754e394f5_643x418.png) ## Jest https://jestjs.io/zh-Hans/ * facebook 靠山 * 基于 Jasmine 至今已经做了大量修改添加了很多特性 * 开箱即用配置少,API 简单 * 支持断言和仿真 * 支持快照(snapshot)测试 * 在隔离环境下测试 * 互动模式选择要测试的模块 * 优雅的测试覆盖率报告,基于 Istanbul * 较新,社区不十分成熟 * 全局环境,比如 describe 不需要引入直接用 * 较多用于 React 项目(但广泛支持各种项目) > [Why Do JavaScript Test Frameworks Use describe() and beforeEach()?](https://www.bignerdranch.com/blog/why-do-javascript-test-frameworks-use-describe-and-beforeeach/) > [Testing JavaScript with Jest](https://flaviocopes.com/jest/#run-jest-with-vs-code) > https://www.valentinog.com/blog/jest/ ## Mocha [Mocha](https://mochajs.org/) 是一个功能丰富的 JavaScript 测试框架,运行在 Node.js 和浏览器上,使得异步测试简单而有趣。Mocha 测试是串行运行的,允许灵活和准确的报告,同时将未捕获的异常映射到正确的测试用例。 默认会自动运行当前项目的 `test` 文件夹下的测试文件。 * 灵活(不包括断言和仿真,自己选对应工具) 流行断言库可选择:[chai](https://www.chaijs.com/api/assert/),[sinon](https://ssh://github.com/sinonjs/sinon) * 社区成熟用的人多,测试各种东西社区都有示例 * 需要较多配置 * 可以使用快照测试,但依然需要额外配置 > [Unit testing Node.js applications using Mocha, Chai, and Sinon](https://blog.logrocket.com/unit-testing-node-js-applications-using-mocha-chai-and-sinon/) ## Jasmine [Jasmine](https://jasmine.github.io/index.html) 是一个针对 JavaScript 的行为驱动开发的测试框架,不依赖于任何其他的 JavaScript 框架或者文档对象模型(DOM),最新版本改进了对 Node.js 的支持,同时还做了一些提升内部质量的工作。 * 开箱即用(支持断言和仿真) * 只支持 BDD * 全局环境 * 不依赖于任何其它的 JavaScript 框架 * 不需要 DOM * 结构简单 * 可以运行在 Node.JS 或者 Html 中 * 基于行为驱动开发 Jasmine ## AVA 未来的测试运行器。 从 Mocha 切换到 AVA 让测试时间从 31 秒下降到 11 秒。测试并发执行强制你写原子测试,意味着测试不需要依赖全局状态或者其他测试的状态,这是一件非常好的事情。 [avajs/zh_CN/readme.md](https://github.com/avajs/ava-docs/blob/master/zh_CN/readme.md) ## Karma [Karma](https://karma-runner.github.io/) 是一个基于 Node.js 的 JavaScript 测试执行过程管理工具(Test Runner)。由 Google 团队开发的一套前端测试运行框架。它不同于测试框架(例如 jasmine,mocha 等),该工具可用于测试所有主流 Web 浏览器,也可以集成到 CI(Continuous integration)工具,还可以和其他代码编辑器一起使用。 Karma 会监控配置文件中所指定的每一个文件,每当文件发生改变,它都会向测试服务器发送信号,来通知所有的浏览器再次运行测试代码。此时,浏览器会重新加载源文件,并执行测试代码。其结果会传递回服务器,并以某种形式显示给开发者。 访问浏览器执行结果,可通过以下的方式: * 手工方式 - 通过浏览器,访问 URL 地址 - http://localhost:9876/ * 自动方式 - 让 karma 来启动对应的浏览器 主要完成以下工作: 1. Karma 启动一个 web 服务器,生成包含 js 源代码和 js 测试脚本的页面; 2. 运行浏览器加载页面,并显示测试的结果; 3. 如果开启检测,则当文件有修改时,执行继续执行以上过程。 ## 其他 如果想要对前端产品进行测试,还需要另外一个工具: * 测试浏览器 -- [Puppeteer](Puppeteer%E5%AD%A6%E4%B9%A0.md) # 前端e2e测试 单元测试 ·业务驱动开发 & 测试驱动开发 ·黑盒测试和白盒测试 ·测试覆盖率 ·前端项目的单测集成 ·Node项目的单测集成 e2e测试 ·前端e2e测试 ## 附录 http://www.daqianduan.com/1845.html 前端测试工具集锦 https://qaseven.github.io/2016/05/24/front-end-tools/ https://www.douban.com/note/509058712/ [前端自动化测试](https://www.baidu.com/s?wd=%E5%89%8D%E7%AB%AF%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95) [如何进行前端自动化测试?](https://www.zhihu.com/question/29922082) [聊聊前端开发的测试](https://zhuanlan.zhihu.com/p/26050231) # 用 Headless Chrome 代替 Phantomjs。 1. 我爸是 Google ,那么就意味不会出现 Phantomjs 近 2k 问题没人维护的尴尬局面。 比 Phantomjs 有更快更好的性能。 2. 有人已经做过实验,同一任务,Headless Chrome 要比现 Phantomjs 更加快速的完成任务,且占用内存更少 3. chrome 对 ECMAScript 2017 (ES8) 支持,同样 headless 随着 chrome 更新,意味着我们也可以使用最新的 js 语法来编写的脚本,例如`async`,`await`等。 4. 完全真实的浏览器操作,chrome headless支持所有chrome特性。 5. 更加便利的调试,我们只需要在命令行中加入 `--remote-debugging-port=9222`,再打开浏览器输入 `localhost:9222` (ip为实际运行命令的ip地址)就能进入调试界面。 Google 最近放出了终极大招—— [Puppeteer 学习](Puppeteer%E5%AD%A6%E4%B9%A0.md) *** # chrome 跨域调试 跨域设置 ~~~ --disable-web-security ~~~ 1. Chrome 桌面快捷方式=》鼠标右键=》属性-》目标后。 2. MyChrome -》高级-》启动参数 `Allow-Control-Allow-Origin:*` [跨域插件](https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi) # 单元测试工具 [Mocha](https://mochajs.org/) [k6](https://k6.io/) 单元测试工具 —— [karma](http://karma-runner.github.io/latest/index.html)(跑测试用例的容器) [jasmine](https://jasmine.github.io/) —— 编写测试用例。 [macaca](https://github.com/alibaba/macaca) —— 多端自动化测试解决方案 # 参考 [测试网](http://www.51testing.com/html/96/category-catid-96.html) [你需要了解的前端测试“金字塔”](http://web.jobbole.com/93120/) [测试你的前端代码 – part1(介绍篇)](http://web.jobbole.com/91123/)