前言
大概是17年的时候,我在整个前端分享会上做一次关于集成测试的分享,但是反响平平。
但是随着业务的继续扩大,项目越来越多,发版上线越来越频繁,想必大家都会有各种各样的痛点。
对于我们电商团队来说,最核心的一点就是要保障整个购买流程的稳定。
但如果每一次的上线都需要去人为的去走一遍整个购买流程是非常浪费精力和时间的。
那么这个时候就需要集成测试来帮忙解决了。
选型
加两个条件:
- 需要在浏览器环境运行,因为我们的页面都是需要跑在浏览器里面的。
- 尽可能的所有浏览器里运行。
一通调研、筛选下来之后,就发现了:WebDriver,全称:Selenium WebDriver 2.0
这里就很有必要讲一下,前端测试的一个发展阶段:
前端自动化测试经历过很多的阶段:
- 0时代:Selenium RC
- 0时代:Selenium WebDriver
Selenium RC
它的实现方式主要是通过构建一个浏览器沙箱,然后通过js注入的方式来实现的。
可以理解为在页面中注入了一段js代码,后面所有页面相关的操作,都是通过执行了这里面的 js 代码去做到的。
正因为这种方式非常依赖浏览器开放给 js 的能力,所以受限非常明显。
我们再看一下 WebDriver
Selenium WebDriver
本身是基于浏览器开放出来的一个能力,一个调用浏览器内核的能力,来达到自动化测试。
它的核心是通过调用对应的浏览器本身的Driver,然后再上层API层面,去抹平不同浏览器的差异。
而本身也慢慢变成了一个标准:https://www.w3.org/TR/webdriver/
Wire Protocol
可以通过三个关键字描述:
- HTTP Protocol
- Restful API
- JSON Data
通过一组 HTTP 接口来提供对外调用的能力。
结束了么?
实际效果
初期的话,效果还是挺好的,各种测试模式看着都能正常运行。
我们把整个代码部署到了一台电脑上。但随着使用变多,发现越来越多的问题:
- 经常动不动失败了。原因各种各样,但主要有两个:一个是调用的 API 莫名其妙错误,一个是本身 Chrome 升级越来越频繁,大概一个月就可能升级一次,对应的我就需要重新下载新的 Chrome Driver。
- 依赖的 Selenium-Standalone 不定期内存溢出。使用的是 Selenium-Standalone 一直启动 WebDriver Server。但这个隔一段时间就内存溢出了。 一直不稳定就导致这套方案一度中断。
重新定位
有句话叫做:什么都想做,就会什么都做不成。
我们做了一个重新的定位:
集成测试的目标是一个流程的功能性测试。可以不是完整的,但应该尽可能包含更多的情况,且不应该包含浏览器兼容性之类的测试。(题外话,兼容性测试本身是比较复杂和繁琐,并且很难说能覆盖到多少)
有了这个新的定位后,我们就能很好的指导我们之后的行动了。
我们重新调整后,把目光转向了Headless Test。
这个时候有两个选择:
- PhantomJS
- Chrome Headless
PhantomJS 辅导这边很早就在使用,特别是在教研那边,我们也使用它做过截图的事情。
但是在用的过程中有各种各样的问题,主要原因在于它本质是模拟浏览器,和真正的浏览器还是有很大的差别,并不能完全模拟真实的用户操作。
很多时候,我们在 PhantomJS 发现一些问题,但是调试了半天发现是 PhantomJS 自己的问题。
当然,现在 PhantomJS 已经不维护了。
然后,说到 Chrome Headless,它的本质上就是 Chromium,只是少了一个 UI Shell。
并且官方开发了一个 Node.js 库:Puppeteer(https://github.com/puppeteer/puppeteer),里面提供了各种高级的 API 接口,让你可以非常方便和自由控制 Chromium。
比 WebDriver 强大太多了。
背靠大树好乘凉,自从调整到了基于 Chrome Headless 后,整个测试再也没有因为底层的不稳定导致测试中的各种问题。
从 PhantomJS 转到 Chrome Headless 可能都看过这么一句话:PhantomJS is dead, long live headless browsers(phantomJs之殇,headless-browsers之生)
但是,除了底层选型和重新定位外,我更想说一说的是我们的集成测试整体架构。
集成测试整体架构
先从流程上看,我们对外提供 HTTP 接口,外部调用后,首先是 新开一个进程,加载对应的测试并执行,最后生成报告的一个过程。
再从模块上看,
首先,是一个基于 KOA 的 Node.js Server,这是一个对外入口,提供了一个外部调用的机制,在里面可以根据自己的需要做不同的处理。
然后,核心在最中间的部分,就是其中集成测试部分。
这套架构的顶层是 Runner,它是负责调度和执行整个测试用例的。
单个 Test(测试体)可以是一个或多个 Case 的集合,而且本身也是基于某个测试框架的,像我们现在主体是采用的 Mocha这套测试框架。
每个 Case 根据自己的需要,会依赖于很多的模块、数据、帮助文件、mock方式来实现。
最底层就是 Puppeteer 帮我们构造整个的测试宿主环境。
最后,就是报告部分,通过最终的执行结果生成我们想要的各种类型报名并发送到我们指定的地方。
PS:这实践中,我们发现整个这套架构是可以适应于各种类似的自动化相关的测试。