# 2.前端自动化测试
测试是一个庞大的主题,包括各种分类的测试,诸如黑盒测试/白盒测试、单元测试/集成测试/端到端测试等。通常程序员在测试自己的代码的时候用得最多的便是单元测试,但是因为测试也是需要代价,很多人是不喜欢写测试的,甚至是一点都不写。
那么是什么原因让大家不愿意写呢?
- 不熟悉
- 浪费时间
- 知识不成体系
- 团队氛围
- 缺少实践
我们要从基础的东西学起,打消对测试的恐惧。
# 测试的分类
在多浏览器的自动化测试,我们多半是进行端到端的测试工作,一小部分是大粒度的单元测试。端到端测试测试模拟用户的行为。在 Web 应用程序中,他们会启动服务器,打开浏览器,模拟用户的行为进行点击、输入、提交等动作,断言浏览器中发生了特定的事情或者是得到了期待的结果,从而让我们相信功能可以正常的运行。
而单元测试根据代码单元的公共 API 运行它们。这些测试需要创建一个类的实例,使用特定的输入调用它的方法,断言被调用的方法达到了预期的效果。在下文中我们会看到这两种测试的实践,当然有时候区分度并不大,可能无法明显地区分哪些是端对端测试哪些是单元测试,有时候他们是混合起来的,不过只要记住我们的目标是保证功能可以正常运行救足够了。
按照软件工程自底而上的概念,前端测试一般分为单元测试(Unit Testing )、集成测试(Integration Testing)和端到端测试(E2E Testing)。从下面的图可以看出,从底向上测试的复杂度将不断提高,另一方面测试的收益反而不断降低的。

关于软件测试分类,可见软件测试的分类
# 测试工具对比
在进行项目实践前,很重要的一项工作是选择合适的技术栈。好比在前端开发时应该选择 React,Vue 还是 Angular 作为框架一样,前端的测试工作也需要选择一套技术栈。很多时候大家在制定技术栈时容易走偏,在选择技术框架时不是选择最合适的框架,而是选择最热门的框架。当然一定程度上热门的框架能反应其受欢迎程度,可能是因为其出众的优点,如较高的开发效率、高效的渲染特性或者是活跃的社区。在前端开发中,很容易有这样的感受,就是只要半个月没有关注业界的最新动态,就感觉恍若隔世,新的解决方案层出不穷,让人喘不过气。
经过几年的前端洗礼之后,就已经过了慌乱的年纪,再也不会盲目地追寻新技术,而转向关注技术背后解决的痛点,原理等。

# 如何选择测试框架
测试框架基本上都做了一件事儿:
- 描述你要测试的东西
- 对其进行测试
- 判断是否符合预期
选择框架会考虑下面的点:
测试框架是否有简明的语法与文档。
Mocha、Jasmine、Jest、AVA、Karma、Nightmare
断言(Assertions):用于判断结果是否符合预期。有些框架需要单独的断言库。
Should.js、chai、expect.js等等,断言库提供了很多语义化的方法来对值做各种各样的判断。当然也可以不用断言库,Node.js中也可以直接使用原生assert库。
适合 TDD / BDD:是否适合 测试驱动型 / 行为驱动型 的测试风格。
BDD(Bebavior Driven Developement,行为驱动测试)和TDD(Testing Driven Developement,测试驱动开发)
BDD和TDD均有各自的适用场景,BDD一般更偏向于系统功能和业务逻辑的自动化测试设计,而TDD在快速开发并测试功能模块的过程中则更加高效,以快速完成开发为目的。下面我们看下BDD和TDD具体的特点:
BDD的特点:
- 从业务逻辑的角度定义具体的输入与预期输出,以及可衡量的目标;
- 尽可能覆盖所有的测试用例情况;
- 描述一系列可执行的行为,根据业务的分析来定义预期输出。例如,expect, should, assert;
- 设定关键的测试通过节点输出提示,便于测试人员理解;
- 最大程度的交付出符合用户期望的产品,避免输出不一致带来的问题。
TDD的特点:
- 需求分析,快速编写对应的输入输出测试脚本;
- 仅在自动测试失败时才编写新代码。
- 重构去除不必要的依赖关系,然后重复测试,最终让程序符合所有要求。
异步测试:有些框架对异步测试支持良好。
使用的语言:大部分 js 测试框架使用 js。
用于特定目的:每个框架可能会擅长处理不同的问题。
是要测试单个功能、单个组件、还是集成化测试?
是要测试GUI逻辑、交互?
是要测试非功能性指标?兼容性?
社区是否活跃。
# 测试工具的类型
测试工具可分为以下功能。有些只为我们提供了一种功能,有些功能为我们提供了一种组合。
为了实现最灵活的集合功能,通常使用多种工具的组合。
提供UI界面或者CLI工具:(Karma (opens new window),Jasmine (opens new window),Jest (opens new window),TestCafe (opens new window),Cypress (opens new window))
CLI工具会给出一系列测试,以及运行这些测试所需的各种配置和脚手架(运行什么浏览器,使用什么babel插件,如何格式化输出等)
提供测试框架(形成文件目录):(Mocha (opens new window), Jasmine (opens new window), Jest (opens new window), Cucumber (opens new window), TestCafe (opens new window), Cypress (opens new window))
提供断言:(Chai (opens new window),Jasmine (opens new window),Jest (opens new window),Unexpected (opens new window),TestCafe (opens new window),Cypress (opens new window))
断言函数检查测试返回的结果是否符合预期
生成,展示测试结果(Mocha (opens new window),Jasmine (opens new window),Jest (opens new window),Karma (opens new window),TestCafe (opens new window),Cypress (opens new window))
快照测试(Jest (opens new window),Ava (opens new window))
快照测试(snapshot testing),测试 UI 或数据结构是否和之前完全一致,通常 UI 测试不在单元测试中
提供仿真(Sinon (opens new window),Jasmine (opens new window),enzyme (opens new window),Jest (opens new window),testdouble (opens new window))
仿真(mocks, spies, and stubs):获取方法的调用信息,模拟方法,模块,甚至服务器
生成测试覆盖率报告 (Istanbul (opens new window), Jest (opens new window), Blanket (opens new window))
提供类浏览器环境(Nightwatch (opens new window), Nightmare (opens new window), Phantom (opens new window), Puppeteer (opens new window), TestCafe (opens new window), Cypress (opens new window))
可视化回归工具(Applitools (opens new window), Percy (opens new window), Wraith (opens new window), WebdriverCSS (opens new window))
# 单元测试类工具
npm trends: 点击链接 (opens new window)

Karma
Karma是一个Runner(即运行环境),具体详细的介绍见 后面的章节Karma
A test runner is the library or tool that picks up an assembly (or a source code directory) that contains unit tests, and a bunch of settings, and then executes them and writes the test results to the console or log files. there are many runners for different languages. See Nunit and MSTest for C#, or Junit for Java.
karma 设计目标主要有下面四点:
高效 扩展性 运行在真实设备 无缝的使用流程
karma 是一个典型的 C/S 程序,包含 client 和 server ,通讯方式基于 Http ,通常情况下,客户端和服务端基本都运行在开发者本地机器上。
一个服务端实例对应一个项目,假如想同时运行多个项目,得同时开启多个服务端实例。
Karma 的优点是能通过插件和配置的方式集成大部分的主流的测试框架和前端库,能方便的一次在多浏览器环境执行测试用例,并集成了测试覆盖率生成功能,生成页面形式覆盖率报告并能导出不同形式的覆盖率报告数据。
它的缺点是,对测试页面环境的搭建和资源文件的加载不是常见的形式,最开始搭建环境时会有很多跟预期不一致的情况,配置不直观。
Jasmine
Jasmine 带有 assertions(断言),spies (用来模拟函数的执行环境)和 mocks (mock 工具),Jasmine 初始化设置简单,同时,如果你需要一些单元功能的时候你仍然可以加一些库进来。
Mocha
Mocha 是一个灵活的库,提供给开发者的只有一个基础测试结构。然后,其它功能性的功能如 assertions, spies和mocks,这些功能需要引用添加其它库/插件来完成。
Jest
被 Facebook 和各种 React 应用推荐和使用,Jest 得到了很好的支持。Jest 也被发现是一个非常快速的测试库在平行测试报告中。
对于小型项目来说你可能在开始的时候不用过多担心,而性能的提高,对于希望全天持续部署的大型应用 app 来说是非常之好的。
而开发人员主要是用 Jest 去测试 React 应用,Jest 可以很容易地集成到其它应用程序中充许你使用更独特的特性在其它地方
快照测试是一个非常好用的工具,去确保你的应用 UI 不会有超出预期的错误,在产品发布替换的期间发生。虽然大部分功能,专门设计都是使用在 React 上。
Jest 有着很广阔的 API 。
AVA
AVA 它的优势是 JavaScript 的异步特性和并发运行测试.
利用了 JavaScript 的异步特性优势,优化了在部署的时间等待
保留了简单的 API 为你提供你所需要的功能。
如果搭配 mocking 来使用它会显得更加友好,但是必须安装一个单独的库。
# E2E测试类工具
npm trends: 点击链接 (opens new window)

# 最佳实践
测试有很多好处,但不代表一上来就要写出100%场景覆盖的测试用例。
最佳的实践:基于投入产出比来做测试
由于维护测试用例也是一大笔开销(毕竟没有多少测试会专门帮前端写业务测试用例,而前端使用的流程自动化工具更是没有测试参与了)。
对于像基础组件、基础模型之类的不常变更且复用较多的部分,可以考虑去写测试用例来保证质量。个
先写少量的测试用例覆盖到80%+的场景,保证覆盖主要使用流程。
一些极端场景出现的bug可以在迭代中形成测试用例沉淀,场景覆盖也将逐渐趋近100%。
但对于迭代较快的业务逻辑以及生存时间不长的活动页面之类的就别花时间写测试用例了,维护测试用例的时间大了去了,成本太高。
大型项目,可以使用Jest快速形成配置并且开始单元测试。
需要测试快照,则可以选择Jest或者Ava。
对于配置性要求高,对测试框架性能有要求的可以选择mocha。
对模拟还原浏览器业务操作有很大的需求的,可以选择nightmare
配合CI工具完成自动化测试、测试覆盖率、测试结果推送。