前端之殇

要是你碰到前端工程师朋友,那聊聊浏览器的兼容性准是没错,这和碰到英国朋友就谈天气是一个道理。大部分程序员朋友们一定会捶胸顿足,连连诉苦,不过如果对方一时语塞,或者欲言又止,请拍拍他/她肩膀说:“没事,过两年出了新浏览器又是一条好汉。”

在前端界,浏览器兼容性是让工程师们头疼的问题,对于经验丰富的人来说,很清楚浏览器有哪些坑,但是对于大部分程序员,最可怕的是代码明明在这个浏览器运行得很好,但是到了另一个浏览器中就不能正常运行了。对于这部分的程序员,保障代码能正常运行的方法便是能尽早发现问题,然后将其解决。

如何进行前端自动化测试?_运维

通常情况下,发现兼容性问题的方法莫过于将程序在各个浏览器中执行一遍,但这是极其浪费人力和时间的,最省力的方法也需要在每次版本的更迭时重复一遍测试工作。对于不同的兼容性要求,测试需要的时间各不相同,若是只支持最新版本的浏览器,那么便测试3、4个浏览器即可,但是对于兼容性要求高的程序,有可能要测试10个浏览器以上。对于中小型公司来说,如果没有专职的测试人员,这样的测试耗时是致命的。若进行严格测试,则会拖慢项目进度,倘若敷衍了事,那程序的质量便没法保证。

本文将作为多浏览器自动化测试的第一篇文章,将以项目A作为例子,给读者从头介绍如何进行本地多浏览的自动化测试工作,包括测试的原理、测试框架的选取、测试工程的搭建和实现等。在下一篇文章中将介绍如何使用云服务实现更多浏览器的测试工作。另外“从入门到不放弃”系列将给读者们带来更多从零开始的前端实践案例,诸如前端组件库设计与实施、项目自动化构建等案例,欢迎大家关注本系列的其他文章。

小窥测试

测试是一个庞大的主题,包括各种分类的测试,诸如黑盒测试/白盒测试、单元测试 /集成测试/端到端测试等。通常程序员在测试自己的代码的时候用得最多的便是单元测试,但是因为测试也是需要代价,很多人是不喜欢写测试的,甚至是一点都不写。当然今天我们不是要讨伐诸位,而是希望读者能从文中受益,从一个测试小白可以自己动手搭建自己的测试工程。

在多浏览器的自动化测试,我们多半是进行端到端的测试工作,一小部分是大粒度的单元测试。端到端测试测试模拟用户的行为。在 Web 应用程序中,他们会启动服务器,打开浏览器,模拟用户的行为进行点击、输入、提交等动作,断言浏览器中发生了特定的事情或者是得到了期待的结果,从而让我们相信功能可以正常的运行。而单元测试根据代码单元的公共 API 运行它们。这些测试需要创建一个类的实例,使用特定的输入调用它的方法,断言被调用的方法达到了预期的效果。在下文中我们会看到这两种测试的实践,当然有时候区分度并不大,可能无法明显地区分哪些是端对端测试哪些是单元测试,有时候他们是混合起来的,不过只要记住我们的目标是保证功能可以正常运行救足够了。

在浏览器的测试中,Selenium 可谓是最重要的工具之一。简单来说Selenium的作用是 "Automate Browsers"——让浏览器可以自动化起来的工具。它提供了统一的接口,让用户可以使用不同的编程语言,调用其接口来模拟用户的操作,例如点击,移动等操作。基本上一切人工操作的行为都可以通过 Selenium 的 API 进行触发操作。我们将 Selenium 看作是人手的代理,帮程序员完成一切用手干的活。

测试的技术方案选择

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

如何进行前端自动化测试?_chrome_02如何进行前端自动化测试?_运维_03


在介绍本文涉及项目的技术栈之前,需要提醒诸位,此处的技术选择并不一定完全适用于诸位的项目,请各位三思而测。目前市场上有众多的测试框架,测试断言库甚至是全套的测试解决方案。Karma、Jasmine 和 Mocha 是大家熟知的测试框架,而 chai, should.js 是流行的断言库,另外在不同的技术社区还有自成一套的测试技术,比如 React 社区中的 Jest 和 Enzyme 都是受开发者喜爱的测试框架和库,最近一些新的并行测试解决方案也日渐流行,如AVA、Intern。本文中的实践来自于项目A,在项目测试前期我们分析了测试需求,我们希望整个测试方案能满足一下要求:


  • 支持端到端测试
  • 对接云测试服务方便
  • 本地测试和云测试切换方便
  • 提供封装的浏览器操作接口
  • 测试用例可以快速迁移到其他框架下执行

考量了以上的需求,我们认为 NightWatch.js 是一款非常合适的测试解决方案。当然其他的测试框架也基本能满足需求,但是从方便易用性上考虑,我们最后采用了 NightWatch.js,该方案不仅提供简易封装的浏览器代理操作 API, 还给我们提供了方便便捷的云测试配置(下一篇文章将着重介绍此内容),就凭这两点就已经非常吸引我们了。对于前端测试新手,强烈推荐试用此框架,让你可以迅速完成曾经畏而却步的测试工作。

项目实践

项目A的本地测试实践是需要分别在两台电脑上的多浏览器中执行测试,两台电脑分别是 Windows 系统和 Mac 系统,包括了 IE 、Firefox(windows/mac)、Chrome(windows/mac)、Safari 等最新的主流浏览器。两台机子的测试是分别执行的,我们通过 Jenkins 分别定期执行机子上的测试任务,将测试结果通过邮件的方式反馈给开发人员。 Jenkins 是一个持续集成的平台,关于如果使用 Jenkins 请各位自己 Google..

在接下来的文章中,我们将只介绍在一台机子上的工程实践,对于多个机子的测试需要将如下的工程部署到不同的机子,再使用诸如 Jenkins 之类的工具进行定期执行就可以。

开始工作前,我们需要将技术关系了然于心。我们在 Nightwatch 框架下使用 Selenium 中的 driver对浏览器进行操作。不同的浏览器有不同的 Driver,整个技术栈图如图1所示:

如何进行前端自动化测试?_前端_04如何进行前端自动化测试?_chrome_05

图1

在图中 Test Runner 即为 Nightwatch,我们使用 Nightwatch 提供封装过的 API 进行 Test Case 的书写。下面我们将从零开始手把手教你如何使用 Nightwatch 启动你的第一个 Test case。

1. 安装测试所需包

在自己的前端项目中安装 Nightwatch.js,并将其保存在 package.json的 devDependencies 中。


npm install nightwatch --save-dev


2. 增加 npm script 入口

在 npm scripts ​ 中加入 test 指令入口,该条指令的具体工作是使用 test.conf.js 的配置,执行名为'A'、'B'、'C'的配置项(若为了直观查看测试的内容,可根据项目的测试浏览器和版本将名字设为 chrome52.0 , safari9.0 这样的名字,此处设为 A,B,C 是避免大家误认为是指令是自动根据名字去寻找匹配的浏览器)。更多命令的详解请参照 Nightwatch 文档。


"scripts": {
...
"test": "./node_modules/.bin/nightwatch -c conf/test.conf.js -e A,B"
...
}


3. 配置 Nightwatch

完成指令入口的配置工作,接下来需要完成 test.conf.js 的配置工作。在本地测试中,我们使用 Selenium 对浏览器进行代理操作。配置使用本地 Selenium 操作本机浏览器 Nightwatch 有三个重点:

  • Selenium 的配置:配置好 Selenium jar 包的路径,该包从 Selenium 的官网上下载,host 和 port 按照下文配置书写。



  • driver 的配置:cli_args 是 Selenium 参数,在这我们指定了 chromedriver 和 geckodriver 的路径,chromedriver 是用来操作 chrome,geckodriver 用来操作 safari 和 firefox(顾名思义,geckodriver 支持基于 gecko 的浏览器),都可以从网上进行下载。在项目A中,我们将其下载到前端下面的 bin 目录下。
  • 测试目标浏览器的配置:也就是A和B,每一个 Object 都是一个配置项,A是测试Chrome浏览器,B是测试 Safari 浏览器,如果没有指定版本,就使用本地最新版,更多的配置可以参考 Nightwatch 文档,可以指定系统、版本,并可以启动、禁用浏览器的某些特性,如 Cookie。


selenium : {
"start_process" : true,
"server_path":"./bin/selenium-server-standalone
-3.4.0.jar",
"host" : "127.0.0.1",
"port" : 4444,
"cli_args": {
"webdriver.chrome.driver": "bin/chromedriver",
"webdriver.gecko.driver" : "bin/geckodriver"
}
},
...
test_settings: {
A: {
desiredCapabilities: {
'browserName': 'chrome'
}
},
B: {
desiredCapabilities: {
'browserName': 'safari'
}
}
}
...



诸位需要根据自己机子的实际情况进行配置,如果是Windows系统,那么将没有safari浏览器 ,而使用 IE 浏览器,这样则会需要 IE 浏览器对应的 driver。

4. 书写测试用例

在各项准备工作完毕后,就只差测试用例了,下面是项目A的一个测试用例的片段,用于检测页面上 id 为 testid 的 DOM 中的内容字符,我们期待字符的长度为 32, 如果该字符为 32 个字符,那么测试通过,否则测试失败。需要注意的是因为此 DOM 是动态插入的,所以在判断其字符前,我们使用 waitForElementVisible 来检查浏览器中 testid 的 DOM 是否已经显示,若在5秒内显示则进行下面的工作,如果没有显示,那么测试也会失败。


module.exports = {
'@tags': ['unit'],
'unit testing' : function (browser) {
browser.url
(`http://localhost:3010/test`)
.waitForElementVisible('#testid', 5000)
.getText("#testid",function(result){
this.assert.equal(result.value.length,32);
});
browser.end();
}
};


5. 运行测试

到此为止,我们简单的测试工程已经搭建完毕。现在我们回过头去,执行我们最开始配置的 test 指令,启动测试任务。你需要在命令中执行:


npm test


如果顺利的话,此时你会看到浏览器自动地打开关闭,很快就能从终端上看到如下的测试结果,图2 展示的是多个测试用例成功的结果,图3展示的是测试失败的结果(如遇到无法测试或者其它异常情况请 Google。:D)。

如何进行前端自动化测试?_云测试_06如何进行前端自动化测试?_运维_07

图2

如何进行前端自动化测试?_运维_08如何进行前端自动化测试?_运维_09

图3

从测试结果中可以查看测试用例的测试结果,包括测试的浏览器、未通过测试的信息详情等。至此,一个从零开始的本地测试实践教程结束。

本地测试与云测试

因为本地浏览器的类型有限,一般我们更多地使用本地的多浏览器测试来完成功能验证的工作,对于要求更严的兼容性测试,我们将采用云测试的方式。云测试即云服务提供商将向我们提供更多的云主机,每台主机上运行着不同版本的浏览器。通过使用云测试服务,我们就能将测试覆盖到更多类型、版本的浏览器。

在下一篇文章中,我们仍以项目A为例子,使用 Nightwatch 框架,在此文章的基础上介绍云测试和云测试工程的搭建。


在上一篇文章中,撸主已手把手教大家如何从零开始构建一个本地自动化测试工程。如果你没有看过上一篇文章,请先逐字阅读。本文将在上一篇文章的基础上主要为大家介绍两个内容:一是如何免费地搭建多机的自动化测试环境,二是如何使用云测试服务进行360度无死角的自动化测试。信息量大,请各位阅后勿焚,动手牢记。

本地测试鞭长莫及

由于一台计算机支持的浏览器种类有限,如一台 mac 上可以安装 safari, chrome, firefox, opera 等,而且通常只能安装一个版本的产品,所以本地测试多用于检验功能逻辑是否正确,或者是检验特定浏览器的特定功能。对于未知的兼容性测试,单凭本地测试是没法进行的。下文中介绍的方法将提供给测试者一种全新的测试体验,通过远程测试的方式对自己的代码进行测试。 远程测试需要搞清楚两个概念,一是客户端 (Client),一是服务端 (Server),Client 是用于运行 test cases 代码的地方,Server 则是浏览器所在地。通过 Server 上的一些 servlet 来连接 Client 和 Server 上的浏览器,实现将 test 中的用例行为在远程端的浏览器上执行。 通过浏览器和 test 执行宿主机的分离,使得test能在更多的浏览器上执行,并且更易于扩展测试浏览器的数量。在下文的实践当中,读者会对 Client 和 Server 有更清楚的了解,在此不再赘述。

自己的云测试环境

如何进行前端自动化测试?_运维_10

既然测试代码要和浏览器环境分割开来,那么我们需要在前文的基础上将浏览器安装到其他的环境中,而不是将浏览器和测试的 Node 测试环境放在同一台机子。安装完成之后需要使用服务端的 Servlet 也就是 Selenium 提供的 webdriver server 将测试环境和浏览器连接起来。具体的步骤如下: 1. 寻找到一台可用的主机: 无论是实体机还是虚拟机都是可以的,不过需要主机可以接入到测试运行主机的网络。

2. 在主机上安装浏览器: 具体安装的浏览器类型和版本根据操作系统和测试需求而定, 例如可以在 windows 操作系统上安装 IE, firefox等浏览器,在 Linux 系统安装 chrome, firefox等浏览器, 在 Mac系统上安装 safari, chrome 等浏览器。

3. 下载对应浏览器的 driver 到Server主机上。因为 selenium 需要使用不同的 driver 来启动不同的浏览器,如同上一篇文章提到的bin目录下的 driver 可执行文件,此时要将需要测试浏览器对应的 driver 下载到 server 上,然后再通过测试工程的配置告诉 selenium-server-standalone 这些 driver 在哪,从而执行它们来操作浏览器。


  • chromedriver (用于 chrome)下载地址: https://sites.google.com/a/chromium.org/chromedriver
  • geckodriver (可用于 firefox, safari)下载地址:https://github.com/mozilla/geckodriver/releases

4. 在主机上下载并启动 Selenium Server: 该 Server 实际上是一个 Java 小程序,用于 client 和 server 之间的通信。首先在 Selenium 的官网上下载 selenium-server-standalone-{VERSION}.jar, 然后启动该 Jar 包。


java -jar selenium-server-standalone-{VERSION}.jar


如果主机没有安装 JRE, 则需要再安装 java 的运行环境或者是直接安装 jdk 。

5. 修改测试项目的配置文件:还记得启动测试时需要指定的配置文件吗?这个配置文件 test.conf.js 非常重要,用于配置 selenium 以及测试的浏览器,当我们改变使用远程server的浏览器作为测试目标时,当然需要修改配置文件。我们需要将配置文件中的 selenium 项修改为如下形式:


selenium : {
"start_process" : true,
//server的ip地址
"host" : "192.168.10.1",
"port" : 4444,
"cli_args": {
//chromedriver 在server主机上的文件路径
"webdriver.chrome.driver": "/home/bin/chromedriver",
//geckodriver 在server主机上的文件路径
"webdriver.gecko.driver" : "/home/bin/geckodriver"
}
}


对于test_settings 的设置请参照上文,然后按照自己安装的浏览器版本进行修改。

6. 启动测试:一切准备好了之后,在client主机上,也就是测试代码运行的机子上便可启动测试。


"scripts": {
...
"test": "./node_modules/.bin/nightwatch -c conf/test.conf.js -e A,B"
...
}


自己搭建测试云环境的过程其实并不复杂,只需要在将 selenium server 和浏览器安装到其他主机即可,对于 client 上的代码不需要改动,只需要改动配置中的 selenium 配置。但是很快测试者会发现,当我们需要测试更多的机子,用手工的方式去维护这些 server 是一件费时费力的事,也消耗了公司的计算资源。有没有更好的办法让我们既可以全面的测试自己的代码又可以不用费尽心思维护主机?答案是有,请继续阅读。

云测试服务

对于繁琐重复的工程任务,商家们总是能想到赚钱的办法,这不对于上文我们碰到的麻烦就有商家提供了相应的产品。该产品为测试者们提供无数个测试浏览器,测试者不需要关心这些浏览器在何处运行,应该怎么样维护,只需要一个服务地址便可以将自己的测试页面跑在这些浏览器上,其实这个服务地址和之前我们自己搭建的 Server ip 类似,只不过如果使用自己的测试云,使用不同的测试主机时,需要手动更改host。而这些商家提供了一个类似分销中心,用于流量分发,所以我们只需要用一个地址便可实现使用不同的主机进行测试。 目前提供此类服务的商家有很多,如 browserstack、saucelabs、crossbrowsertesting 等,大家可以根据自己手头黄金和测试的需要选择性价比高的服务。本文将使用 browserstack 作为例子为大家科普此类服务,不过它并不是撸主的金钱爸爸,请大家放下水文的猜疑。

如何进行前端自动化测试?_chrome_11

根据我们自行搭建云测试环境的经验,我们将 browserstack 的测试后台架构猜想为下图所示。我们不关心该架构是否是真实的实现,但是这是合理的理论猜想,希望此图能让我们对此服务有个大概的技术了解:

如何进行前端自动化测试?_前端_12

browserstack 为用户提供了自动化测试、实时交互测试、截图等服务,关于具体的服务细节请移步官网。本节将主要介绍如何使用其自动化测试服务,会稍微提及实时交互测试的功能。那接下来便开始我们的云测试使用体验: 首先在其[网站](https://www.browserstack.com​)上注册账号,点击最上方的导航栏中的 Automate,跳转页面后在新页面左侧最上方点击 ”Username and Access Keys”,便可看到用于使用云测试服务的用户名和key,我们将使用此auth来修改测试配置。 现在回到我们的测试项目,对 test.conf.js 的 selenium 项进行修改,并添加 common_capabilities 项,用于配置云服务的信息。


selenium : {
"start_process" : false,
"host" : "hub-cloud.browserstack.com",
"port" : 80
},
common_capabilities: {
'build': 'nightwatch-browserstack
',
// Browserstack 的 username 对应配置项
'browserstack.user': process.env.BROWSERSTACK_USERNAME',
// Browserstack 的 key 对应配置项
'browserstack.key': process.env.BROWSERSTACK_ACCESS_KEY,
'browserstack.debug': true,
'browserstack.local': true
}


连接云测试服务的配置工作完成后,我们需要指定测试的浏览器种类和版本。如果有不指定的字段,云服务会有缺省值来填充,例如配置中没有指定操作系统,云服务则会自动选择最快的一个测试机,而不管浏览器所在的操作系统。再例如当没指定测试浏览器的版本时,云服务则会测试最新版本的浏览器。官网上的文档提供了所有可提供测试的浏览器种类和版本,为了说明方便,我们现在只指定浏览器种类,不规定版本。简要的浏览器配置项如下:


...
safari: {
desiredCapabilities: {
browserName: 'safari'
}
},
ie: {
desiredCapabilities: {
browserName: 'ie'
}
},
...
ios: {
desiredCapabilities: {
browserName: 'iPhone'
}
}
...
}


以上工作做完之后便可以启动测试了,是不是so easy。除了命令行返回的测试结果之外,browsertack 自动化测试还为我们提供了测试回放等。如果发现测试出错,可以通过商家提供的在线实时测试来进行调试,这也是一个非常方便的功能。


如何进行前端自动化测试?_前端_13


如何进行前端自动化测试?_运维_14



有的放矢地测试

阅读完自动化测试的文章,相信大家已经迫不及待想体验云测试的便利。在各位动手之前,有一些温馨提示需要告知大家。首先这些云测试服务因为由国外服务商提供,所以网络延时有些时候会过高,测试可能会出现超时的情况,请选择网络较好的主机来运行测试用例。其次是因为自动化测试会让大家写测试用例上瘾,反正测试扔上去测就好,但是撸主认为测试人员还是要清楚地划分测试的粒度,有些测试用例比如细粒度的单元测试和端对端的测试,有很多测试覆盖的都是同样的代码,这样的测试其实是浪费的,所以在明确目标之后,还需要精心设计测试用例。最后如有不懂请先 google,其他不能 google 的问题欢迎和撸主交流,文章若有错请指教。