vue-cli 脚手架基于Nightwatch的端到端测试环境的过程


Posted in Javascript onSeptember 30, 2018

不同公司和组织之间的测试效率迥异。在这个富交互和响应式处理随处可见的时代,很多组织都使用敏捷的方式来开发应用,因此测试自动化也成为软件项目的必备部分。测试自动化意味着使用软件工具来反复运行项目中的测试,并为回归测试提供反馈。

端到端测试又简称E2E(End-To-End test)测试,它不同于单元测试侧重于检验函数的输出结果,端到端测试将尽可能从用户的视角,对真实系统的访问行为进行仿真。对于Web应用来说,这意味着需要打开浏览器、加载页面、运行JavaScript,以及进行与DOM交互等操作。简言之,单元测试的功能只能确保单个组件的质量,无法测试具体的业务流程是否运作正常,而E2E却正好与之相反,它是一个更高层次的面对组件与组件之间、用户与真实环境之间的一种集成性测试 。

E2E测试的意义在于可以通过程序固化和仿真用户操作,对于开发人员而言,基于E2E测试能极大地提高Web的开发效能,节约开发时间。

先来看看如果没有E2E测试下的一次从开发到手工测试成功的过程:

vue-cli 脚手架基于Nightwatch的端到端测试环境的过程

这个过程还属于简化过的,还没有包括在观察结果时要打开浏览器的调试窗口观看某些内部的运行变量或者网页代码结构。整个过程都是纯人工操作,人工操作最大的问题是一个程序可能要调试好几次,同样的操作就要重复数遍。即使有严格的规定,程序员们大多都还是随便地做“通过”式操作,尤其在输入样本数据时,绝大多数的程序员几乎都是乱输,出现得最多的就是各种随意的数字或者是“aaa”、“asd”、“aws”这样毫无意义的字符。以这种方式开发出来的程序在验收时产品经理或者客户会经常说一句话:“我上次试过是没有问题的!”这样的失误归根结底不在程序员本身,因为这是一种人性!一个人如果重复多次自己都觉得毫无意义的动作时,要不就逃避不做,如果不能逃避就会消极对待。

所以我们应该用更高效、更能弥补人性化缺陷和更有意义的办法来处理,这就是E2E测试,先来看看如果使用E2E测试后的开发过程将会变成什么:

vue-cli 脚手架基于Nightwatch的端到端测试环境的过程

从运行测试开始,所有的一切都是自动的!这就是最大的区别,还有更重要的一点是,当我们要写出E2E测试时就需要对操作需求有深刻的理解,在这一过程中还有很大的机会对用户的操作进行优化,从而提高用户体验。

 Nightwatch

vue-cli的webpack模板也为我们准备了一个当下很流行的E2E测试框架——Nightwatch。

Nightwatch是一套新近问世的基于Node.js的验收测试框架,使用Selenium WebDriver API以将Web应用测试自动化。它提供了简单的语法,支持使用JavaScript和CSS选择器来编写运行在Selenium服务器上的端到端测试。

这个框架在配置好后的具体工作流程如下图所示。

vue-cli 脚手架基于Nightwatch的端到端测试环境的过程

Nightwatch采用Fluent interface模式(https://en.wikipedia.org/wiki/Fluent_interface)来简化端到端测试的编写,语法非常简洁易懂,正如以下代码所示。

this.demoTestGoogle = function (browser) {
 browser
  .url('http://www.google.com')
  .waitForElementVisible('body', 1000)
  .setValue('input[type=text]', 'nightwatch')
  .waitForElementVisible('button[name=btnG]', 1000)
  .click('button[name=btnG]')
  .pause(1000)
  .assert.containsText('#main', 'The Night Watch')
  .end();
}

我们可以从Nightwatch网站找到当前提供特性的列表:

● 简单但强大的语法。只需要使用JavaScript和CSS选择器,开发者就能够非常迅捷地撰写测试。开发者也不必初始化其他对象和类,只需要编写测试规范即可。

● 内建命令行测试运行器,允许开发者同时运行全部测试——分组或单个运行。

● 自动管理Selenium服务器;如果Selenium运行在另一台机器上,那么也可以禁用此特性。

● 支持持续集成:内建JUnit XML报表,因此开发者可以在构建过程中,将自己的测试与系统(例如Hudson或Teamcity等)集成。

● 使用CSS选择器或Xpath,定位并验证页面中的元素或是执行命令。

● 易于扩展,便于开发者根据需要,实现与自己应用相关的命令。

配置 Nightwatch

要了解Nightwatch的配置和用法,与前文介绍Mocha一样,应该先从工程结构入手。

工程结构

.
└── test
      └── e2e
            ├── custom-assertions     // 自定义断言
            │    └── elementCount.js
            ├── page-objects          // 页面对象文件夹
            ├── reports               // 输出报表文件夹
            ├── screenshots           // 自动截屏
            ├── nightwatch.conf.js    // nightwatch 运行配置
            ├── runner.js             // 运行器
            └── specs                 // 测试文件
                  └── test.spec.js

以上是vue-cli为我们自动创建的Nightwatch工程结构,specs是测试文件存放的文件夹,nightwatch.conf.js是Nightwatch的运行配置文件。其他的目录将会在具体的章节逐一地进行讲述。

基本配置

Nightwatch的配置项都集中在nightwatch.conf.js中,其实这个配置也可以是一个JSON格式,采用JSON格式只需要简单地对配置项写入一些常量即可。但使用模块的方式进行配置可以执行一些额外的配置代码,这样则显得更为灵活。以下是我调整过的nightwatch.conf.js文件内容:

require('babel-register');
var config = require('../../config');
var seleniumServer = require('selenium-server');
var phantomjs = require('phantomjs-prebuilt');
module.exports = {
 "src_folders": ["test/e2e/specs"],
 "output_folder": "test/e2e/reports",
 "custom_assertions_path": ["test/e2e/custom-assertions"],
 "page_objects_path": "test/e2e/page-objects",
 "selenium": {
  "start_process": true,
  "server_path": seleniumServer.path,
  "port": 4444,
  "cli_args": {
   "webdriver.chrome.driver": require('chromedriver').path
  }
 },
 "test_settings": {
  "default": {
   "selenium_port": 4444,
   "selenium_host": "localhost",
   "silent": true,
   launch_url:"http://localhost:" + (process.env.PORT || config.dev.port),
   "globals": {
   }
  },
  "chrome": {
   "desiredCapabilities": {
    "browserName": "chrome",
    "javascriptEnabled": true,
    "acceptSslCerts": true
   }
  },
  "firefox": {
   "desiredCapabilities": {
    "browserName": "firefox",
    "javascriptEnabled": true,
    "acceptSslCerts": true
   }
  }
 }
}

Nightwatch的配置分为以下三类:

● 基本配置;

● Selenium配置;

● 测试环境配置。

在配置模块中的所有根元素配置项都属于基本配置,用于控制Nightwatch的全局性运行的需要。下表为Nightwatch的基本配置项的详细说明。

vue-cli 脚手架基于Nightwatch的端到端测试环境的过程

Selenium 配置

Selenium是一组软件工具集,每一个工具都有不同的方法来支持测试自动化。大多数使用Selenium的QA工程师只关注一两个最能满足他们项目需求的工具。然而,学习所有的工具你将有更多选择来解决不同类型的测试自动化问题。这一整套工具具备丰富的测试功能,很好地契合了测试各种类型的网站应用的需要。这些操作非常灵活,有多种选择来定位UI元素,同时将预期的测试结果和实际的行为进行比较。Selenium一个最关键的特性是支持在多浏览器平台上进行测试。

Selenium诞生于2004年,当在ThoughtWorks工作的Jason Huggins在测试一个内部应 用时,作为一个聪明的家伙,他意识到相对于每次改动都需要手工进行测试,他的时间应该用得更有价值。他开发了一个可以驱动页面进行交互的JavaScript库,能让多浏览器自动返回测试结果。那个库最终变成了Selenium的核心,它是Selenium RC(远程控制)和Selenium IDE所有功能的基础。Selenium RC是开拓性的,因为没有其他产品能让你使用自己喜欢的语言来控制浏览器。

Selenium是一个庞大的工具,所以它也有自己的缺点。由于它使用了基于JavaScript的自动化引擎,而浏览器对JavaScript又有很多安全限制,有些事情就难以实现。更糟糕的是,网站应用正变得越来越强大,它们使用了新浏览器提供的各种特性,都使得这些限制让人痛苦不堪。在2006年,一名Google的工程师Simon Stewart开始基于这个项目进行开发,这个项目被命名为WebDriver。此时,Google早已是Selenium的重度用户,但是测试工程师们不得不绕过它的限制。Simon需要一款能通过浏览器和操作系统的本地方法直接和浏览器进行通话的测试工具,来解决JavaScript环境沙箱的问题。WebDriver项目的目标就是要解决Selenium的痛点。

Selenium 1 (又叫Selenium RC或Remote Control)在很长一段时间内,Selenium RC都是最主要的Selenium项目,直到WebDriver和Selenium合并而产生了最新且最强大的Selenium 2。Seleinum 1仍然被活跃地支持着(更多是维护),并且提供一些Selenium 2短时间内可能不会支持的特性,包括对多种语言的支持(Java、JavaScript、Ruby、PHP、Python、Perl和C#)和对大多数浏览器的支持。

Selenium 2 (又叫Selenium WebDriver)代表了这个项目未来的方向,也是最新被添加到Selenium工具集中的。这个全新的自动化工具提供了很多了不起的特性,包括更内聚和面向对象的API,并且解决了旧版本限制。Selenium和WebDriver的作者都赞同两者各具优势,而两者的合并使得这个自动化工具更加强健。Selenium 2.0正是于此的产品。它支持WebDriver API及其底层技术,同时也在WebDriver API底下通过Selenium 1技术为移植测试代码提供极大的灵活性。此外,为了向后兼容,Selenium 2仍然使用Selenium 1的Selenium RC接口。

你可以到http://selenium-release.storage.googleapis.com/index.html下载Selenium的各个稳定版本。

在Vue项目中如果使用vue-cli,那么Nightwatch将不需要进行任何的附加配置,否则你需要在命令行内安装Selenium的包装类库:

$ npm i selenium-server -D

Nightwatch能引导Selenium的启动,实际上我们并没有必要去修改Selenium服务器的默认运行配置,在nightwatch.conf.js配置文件中只需要声明Selenium服务器的二进制执行 文件的具体路径即可,这个可以从selenium-server包提供的Selenium包装对象的path属性中获取,而无须
将本机的物理路径写死到配置文件内。

var seleniumServer = require('selenium-server');
module.exports= {
 "selenium": {    
  "start_process": true,
  "server_path": seleniumServer.path,
  "port": 4444,
  "cli_args": {
   "webdriver.chrome.driver": require('chromedriver').path
  }
 },
 // ... 省略
}

以下是Selenium的详细配置项说明:

vue-cli 脚手架基于Nightwatch的端到端测试环境的过程

 cli_args 的配置

● webdriver.firefox.profile:Selenium默认为每个会话创建一个独立的Firefox配置方案。如果你希望使用新的驱动配置可以在此进行声明。

● webdriver.chrome.driver:Nightwatch同样可以使用Chrome浏览器加载测试,当然你要先下载一个ChromeDriver的二进制运行库对此进行支持。此配置项用于指明ChromeDriver的安装位置。除此之外,还需要在test_settings配置内使用desiredCapabilities对象为Chrome建立配置方案。

● webdriver.ie.driver:Nightwatch也支持IE,其作用与用法与Chrome相同,此处则不过多赘述。

 测试环境配置

test_settings内的项目将应用于所有的测试实例,在E2E测试中我们可以通过Nightwatch提供的默认实例对象browser获取这些配置值,vue-cli为我们创建了default、firefox和chrome三个环境配置项,default配置是应用于所有环境的基础配置选项,其他的配置项会自动覆盖与default相同的配置值。

firefox和chrome这两个配置项是对两种浏览器的驱动进行描述和配置。对于其他语言或框架而言它们也是常客,但由于性能太低,在实战中通常只是个摆设,下文中我将会介绍一种实战效率更高的无头浏览器PhantomJS,对其取而代之。

不要被vue-cli创建默认配置所迷惑,test_settings并不单单只是对浏览器的一些基本运行参数的配置,它正确的用法是对E2E测试环境的配置。单元测试只能运行于开发环境内,而E2E却可以运行于本地环境与网络环境,更准确地说是开发环境与生产环境。所以这个配置项可以用以下的方式进行设置:

"test_settings": {
  "default": {
   "selenium_port": 4444,
   "selenium_host": "localhost",
   "silent": true,
   launch_url:"http://localhost:" + (process.env.PORT || config.dev.port),
   "globals": {}
  },
  "dev": {
   "desiredCapabilities": {
    "browserName": "chrome",
    "javascriptEnabled": true,
    "acceptSslCerts": true
   }
  },
  "production": {
   "launch_url":"http://www.your-domain.com"
   "desiredCapabilities": {
    "browserName": "firefox",
    "javascriptEnabled": true,
    "acceptSslCerts": true
   }
  }
 }

虽然与原有的配置只是在用词上做了一点点改变,但用词的改变将会彻底地改变我们对其的认知与思路!

下表是测试环境配置项的详细说明:

vue-cli 脚手架基于Nightwatch的端到端测试环境的过程

 执行 E2E 测试

vue-cli已经在package.json中配置了运行测试的指令:

$ npm run e2e

这个指令是默认启用Chrome运行环境的,如果指定运行环境可使用--env选项:

$ npm run e2e --env

使用无头浏览器 PhantomJS

vue-cli webpack脚手架模板非常好用,它将环境的复杂性降低了很多,但是却没有很好地诠释它里面采用的每个模块的理由和功能,以及它们的使用特点。这对于入门者来说确实是将门槛降到最低点,但从工程化开发的角度来说,只知道有这些环境或者工具的存在是远远不够的,在Nightwatch中就埋了一个这样的坑。

我们的开发环境在配置Mocha和Karma时就已经安装了PhantomJS,但如果你细读Nightwatch的默认配置会惊奇地发现根本没有采用PhantomJS,只是配置了Chrome和Firefox!问题何在?一个字:慢!

我曾用一台2013年版标准配置(i5CPU、8GB内存、1TB HDD硬盘)的iMac跑本书下一章中的示例程序,运行一次的实际时间是15秒左右!仅仅一次就得15秒,那可以想象我们开发一个场景最少要做多少次的运行?Chrome的启动是很慢的,我们做E2E这种自动化测试如果用真实浏览器的话

只能将性能拖下来,生命不能耗费在毫无意义的等待中!所以我们才会选择PhantomJS!没有默认配置PhantomJS作为主浏览器是这个环境的最大败笔。

办法总比问题多,所以如果没有,我们还可以自己动手来配置,其实方法也很简单。打开nightwatch.conf.js,在test_settings配置段的下方加入以下的内容:

"test_settings": {
 "default": {
  // ...
 }
},
"phantom":{
 "desiredCapabilities": {
  "browserName": "phantomjs",
  "javascriptEnabled": true,
  "acceptSslCerts": true,
  "phantomjs.page.settings.userAgent" : "Mozilla/5.0 (Macintosh; Intel MacOS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36",
  "phantomjs.binary.path":"node_modules/phantomjs-prebuilt/bin/phantomjs"
 }
}

Nightwatch是通过Selenium加载一个GhostDriver来引导PhantomJS浏览器的,上面的内容就相当于告诉Selenium加载一个GhostDriver,可执行程序则指向npm上安装的phantomjs-prebuilt包,再通过这个包来引导安装在本机上的PhantomJS启动。

按上文这样来引用PhantomJS的二进制程序的地址非常难看,还有原生配置中的Selenium执行程序地址也是一样的,这里介绍一个更DRY的方法来处理这些路径:

var seleniumServer = require('selenium-server');
 var phantomjs = require('phantomjs-prebuilt');
 module.exports = {
  // ...省略
  "selenium": {
   // ... 省略
   "server_path": seleniumServer.path,
  },
  "test_settings": {
   // ... 省略
   "phantom": {
    "desiredCapabilities": {
     // ... 省略
     "phantomjs.binary.path": phantomjs.path
    }
   }
   // ... 省略
  }
}

 做完这个简单的优化后就可以打开runner.js文件找到:

if (opts.indexOf('--env') === -1) {
 opts = opts.concat(['--env', 'chrome'])
}

 将chrome改为phantom就行了:

if (opts.indexOf('--env') === -1) {
 opts = opts.concat(['--env', 'phantom'])
}

重新加载测试程序,在同一台iMac上的运行速度直接降到了5秒,测试运行速度提升了3倍!如果你有配置更好的机器,将硬盘换成SSD之后会有更惊人的速度。

Nightwatch 与 Cucumber

如果你正在开发的项目的业务复杂性不大,可以直接使用Nightwatch推荐的链式调用写法。但是当这种做法真正应用在业务流程较多,或者业务操作相对复杂的应用场景时,你会觉得总有写不完的E2E测试,因为这么做E2E测试是没有办法一次性覆盖所有需求的!

E2E测试其实是行为式驱动开发的实现手法,如果跳过了行为式驱动开发的分析部分直接编写E2E,其结果只能是写出一堆严重碎片化的测试场景,甚至会出现很多根本不应该出现的操作。

幸好Nightwatch具有很好的扩展性与兼容性,能集成最正统的BDD测试框架Cucumber(https://cucumber.io/)。Cucumber是原生于Ruby世界的BDD框架,但它也有很多的语言实现版本,我们可以安装一套专门为Nightwatch编写的Cucumber版本——nightwatch-cucumber(https://github.com/mucsi96/nightwatch-cucumber)。本章只介绍关于环境与工具的配置,而关于如何来应用BDD,内容已经超出了本书的知识范围,如果有兴趣的话可以参考《攀登架构之巅》一书中行为式驱动开发的章节内容。

$ npm i nightwatch-cucumber -D

然后在~/test/e2e/nightwatch.conf.js文件中加入对Cucumber的配置:

// ... 省略
 require('babel-register');
 require('nightwatch-cucumber')({
 nightwatchClientAsParameter: true,
  featureFiles: ['test/e2e/features'],
  stepDefinitions: ['test/e2e/features/step_definitions'],   
  jsonReport: 'test/e2e/reports/cucumber.json',
  htmlReport: 'test/e2e/reports/cucumber.html',
  openReport: false
 });

总结

以上所述是小编给大家介绍的vue-cli 脚手架基于Nightwatch的端到端测试环境的过程,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
JQuery Tips(2) 关于$()包装集你不知道的
Dec 14 Javascript
jquery的flexigrid无法显示数据提示获取到数据
Jul 19 Javascript
多种方式实现JS调用后台方法进行数据交互
Aug 20 Javascript
JavaScript 语言基础知识点总结(思维导图)
Nov 10 Javascript
使用jQuery实现验证上传图片的格式与大小
Dec 03 Javascript
Javascript基础教程之if条件语句
Jan 18 Javascript
JavaScript事件学习小结(一)事件流
Jun 09 Javascript
Node.js中的require.resolve方法使用简介
Apr 23 Javascript
vue.js移动端app之上拉加载以及下拉刷新实战
Sep 11 Javascript
JavaScript实现简单动态进度条效果
Apr 06 Javascript
vue实现通讯录功能
Jul 14 Javascript
JS实现可针对算术表达式求值的计算器功能示例
Sep 04 Javascript
对angularJs中ng-style动态改变样式的实例讲解
Sep 30 #Javascript
使用angularjs.foreach时return的问题解决
Sep 30 #Javascript
angular将html代码输出为内容的实例
Sep 30 #Javascript
详解Vue.js iview实现树形权限表(可扩展表)
Sep 30 #Javascript
对angularJs中$sce服务安全显示html文本的实例
Sep 30 #Javascript
vue  自定义组件实现通讯录功能
Sep 30 #Javascript
对angularJs中2种自定义服务的实例讲解
Sep 30 #Javascript
You might like
PHP的开合式多级菜单程序
2006/10/09 PHP
模仿OSO的论坛(一)
2006/10/09 PHP
php将字符串转换成16进制的方法
2015/03/17 PHP
PHP用FTP类上传文件视频等的简单实现方法
2016/09/23 PHP
Laravel定时任务的每秒执行代码
2019/10/22 PHP
LBS blog sql注射漏洞[All version]-官方已有补丁
2007/08/26 Javascript
innerhtml用法 innertext用法 以及innerHTML与innertext的区别
2009/10/26 Javascript
jQuery 网易相册鼠标移动显示隐藏效果实现代码
2013/03/31 Javascript
JavaScript简介
2015/02/15 Javascript
jquery获取及设置outerhtml的方法
2015/03/09 Javascript
基于Jquery实现表单验证
2020/07/20 Javascript
JS及PHP代码编写八大排序算法
2016/07/12 Javascript
JS实现将数字金额转换为大写人民币汉字的方法
2016/08/02 Javascript
全面解析标签页的切换方式
2016/08/21 Javascript
纯js实现隔行变色效果
2017/11/29 Javascript
vue2.0 中使用transition实现动画效果使用心得
2018/08/13 Javascript
JS数组求和的常用方法总结【5种方法】
2019/01/14 Javascript
element-ui table行点击获取行索引(index)并利用索引更换行顺序
2020/02/27 Javascript
Python入门教程之if语句的用法
2015/05/14 Python
Python 闭包的使用方法
2017/09/07 Python
Python设计模式之抽象工厂模式原理与用法详解
2019/01/15 Python
Python实现的银行系统模拟程序完整案例
2019/04/12 Python
tensorflow estimator 使用hook实现finetune方式
2020/01/21 Python
python-docx文件定位读取过程(尝试替换)
2020/02/13 Python
ASOS英国官网:英国在线时装和化妆品零售商
2017/05/19 全球购物
工程班组长岗位职责
2013/12/30 职场文书
电子商务应届生自我鉴定
2014/01/13 职场文书
时尚休闲吧创业计划书
2014/01/25 职场文书
护士求职信范文
2014/05/24 职场文书
财务管理专业毕业生求职信
2014/06/02 职场文书
村党组织公开承诺书
2015/04/30 职场文书
机关干部正风肃纪心得体会
2016/01/15 职场文书
创业计划书之餐饮馄饨店
2019/07/18 职场文书
浅谈Python numpy创建空数组的问题
2021/05/25 Python
Python 多线程处理任务实例
2021/11/07 Python
ubuntu下常用apt命令介绍
2022/06/05 Servers