测试,尤其是自动化测试在现代 WEB 工程中有着非常重要的角色,与交付过程集成良好的自动化测试流程可以在新版发布时帮你快速回归产品功能,也可以充当产品文档。测试因粒度不同又可以分为单元测试、接口测试功能测试。在 WEB 领域,功能测试亦称为端到端测试(End to End Test,简称 E2E 测试),笔者在本文中会结合自身实践和 GitHub 趋势对比受欢迎的 Node.js E2E 测试解决方案,首先我们按 GitHub 的 star 总数量排序,取前 5 名列举如下(注意:你阅读本文时 star 的数量可能已经不是新的)。
  · CasperJS— 6460 个 star,官网,http://casperjs.org
  · Protractor— 6408 个 star,官网,http://www.protractortest.org
  · Nightwatch.js— 6121 个 star,官网,http://nightwatchjs.org
  · TestCafe— 2268 个 star,官网,https://devexpress.github.io/testcafe
  · CodeceptJS— 1087 个 star,官网,http://codecept.io
  然后分别从环境搭建、测试编写、测试报告等方面来直观展示这 5 个 E2E 测试框架,期望能够对做测试框架选型的同学有帮助。为了更客观的体现各测试框架的特点,笔者设计了一些包含 E2E 测试中常用操作的测试用例,分别使用不同的框架来编写。E2E 测试的常用操作如下:
  · 打开网页,跳转网页:打开 Github 的首页;
  · 填写输入框,提交表单:键入搜索词,提交搜索表单;
  · 元素单击等操作:单击搜索结果的第一项;
  · 元素数量、属性检视:确认搜索结果展示了 10 条;
  · 页面运行环境检视:确认页面的地址是正确的;
  CasperJS
  CasperJS 是 star 数高的测试框架,也是笔者早开始采用的 E2E 测试框架,使用 Python 编写,虽不算是严格意义上的原生 Node.js 解决方案,但因为能够使用 npm 安装,且能够很好的与 Node.js 工具链组合使用,笔者还是把它列在了这里。其特别之处在于只能与无界面浏览器(Headless Browser)组合使用,比如 PhantomJS 和 SlimerJS,这也让 CasperJS 的优势显而易见:测试运行速度比真实浏览器快不少,且你不需要在持续集成系统中安装各种浏览器或者某个浏览器的不同版本;潜在的坑在于,无界面浏览器的表现有时和真实浏览器不完全相同,会带来某些难以排查解决的浏览器兼容问题。
  安装步骤
  · 安装 Python 2.6 或更高版本
  · 安装 PhantomJS:npm install -g phantomjs
  · 安装 CasperJS:npm install -g casperjs
  编写测试
  如果使用 ES6 之前的风格来编写 CasperJS 测试,代码看起来会显得非常臃肿,而实际上 CasperJS 也不支持任何 ES6/ES7 的新语法,除非你在运行测试之前自己对代码进行预编译,实际代码如下:
casper.test.begin('Github Search', function suite(test) {
casper.start('https://github.com', function () {    // 打开首页
test.assertVisible('.js-site-search-form', 'should search input visible');
this.fill('.js-site-search-form', { q: 'casperjs' }, true); // 键入搜索词、并提交
});
casper.then(function () {
test.assertEval(function() {    // 确认搜索结果是 10
return __utils__.findAll('.repo-list-item').length >= 10;
}, 'should show 10 results');
});
casper.then(function () {
this.click('.repo-list-item h3 a'); // 点击第1条结果
});
var location = null;
casper.then(function () {   // 这里是取环境变量
test.assertVisible('.repository-content', 'should repo detail visible');
location = this.evaluate(function () {
return window.location;
});
});
casper.then(function () {   // 确认目前跳转到了 casperjs 官方仓库
test.assertEquals(location.pathname, '/casperjs/casperjs', 'should casperjs repo found');
});
casper.run(function () {
test.done();
});
});
  因为 CasperJS 对 CoffeeScript 有天然的支持,熟悉 CoffeeScript 的同学可以尝试使用 CoffeeScript 编写测试,或者使用这个工具转换为 CoffeScript。
  运行测试
  casperjs test casperjs/test.js
  查看报告
  测试通过

  测试失败

  Protractor
  Protractor 是 Angular 官方正在使用的 E2E 测试框架,可以说是专门为 Angular 定制,内置了各种可以选择、操作 Angular 元素的便捷方法,如果你的应用基于 Angular 开发,使用它可以减少很多重复代码(显然类似的便利在其他框架中也有支持)。对于 Angular 的重度使用者,Protractor 会是非常明智的选择,不同于 CasperJS 的是 Protractor 在真实浏览器中运行测试代码。此外,Protractor 内置的页面加载等待的功能,在 CasperJS 中需要自己设置合理的超时。相比于本文列出的其他框架,Protractor 的明显优势是测试用例的组织方式可以自由使用 Jasmine 或者 Mocha。
  安装步骤
  · 安装 JDK
  · 安装 Protractor:npm install –g protractor
  · 初始化 WebDriver Manager:webdriver-manager update
  · 创建配置文件
  编写测试
  Protractor 默认开启了等待 Angular 加载并初始化完成的功能,如果你测试的不是 Angular 应用,则需要关闭这个功能,测试代码示例如下:
describe('angularjs homepage todo list', function () {
browser.ignoreSynchronization = true;   // 不启用智能等待,因为 github 不是用 angluar 编写的
browser.get('https://github.com');
it('should search input visible', function () {
var searchInput = element(by.className('js-site-search-focus'));
var searchForm = element(by.className('js-site-search-form'));
expect(searchInput.isDisplayed()).toEqual(true);
searchInput.sendKeys('protractor');
searchForm.submit();
});
it('should show 10 results', function () {
var searchList = element.all(by.className('repo-list-item'));
expect(searchList.count()).toEqual(10);
element(by.css('.repo-list-item h3 a')).click();
});
it('should repo detail visible', function () {
var repoContent = element.all(by.className('repository-content'));
expect(repoContent.isDisplayed()).toEqual([true]);
});
it('should protractor repo found', function (done) {
browser.executeScript(function () {
return window.location;
}).then(function (location) {
expect(location.pathname).toEqual('/angular/protractor');
done();
});
});
});
  运行测试
  · 运行 WebDriver Manager: webdriver-manager start
  · 运行测试:protractor protractor.config.js
  查看报告
  测试通过

  测试失败

  Nightwatch
  同样流行的 Nightwatch,可以认为是 Protractor 的主要竞争对手,使用 Nigthwatch 编写的代码非常简洁,但是你需要手动在测试代码中添加合适的等待来保障测试的稳定,而 Protractor 和 TestCafe 则提供了内置的支持;Nightwatch 的主要劣势在于繁琐的安装步骤,可能部分同学看到这个安装文档或者下面的安装步骤知难而退了。
  安装步骤
  · 安装 JDK,版本 7 以上
  · 下载 Selenium: selenium-server-standalone-{VERSION}.jar,复制到测试目录
  · 下载 WebDriver for Google Chrome,复制到测试目录
  · 安装 Nightwatch: npm install -g nightwatch
  · 创建配置文件,需要在配置中声明 chromewebdriver 的地址;
  编写测试
module.exports = {
'Github Search': function (browser) {
browser // 打开首页、填写搜索词、提交搜索表单
.url('https://github.com')
.assert.visible('.js-site-search-focus', 'should search input visible')
.setValue('.js-site-search-focus', 'nightwatch')
.submitForm('.js-site-search-form')
.pause(1000);
browser.execute(function () {   // 确认展示 10 条搜索结果
return document.querySelectorAll('.repo-list-item').length;
}, function (args) {
browser.assert.equal(args.value, 10, 'should show 10 results');
});
browser.click('.repo-list-item h3 a').pause(1000);
browser.assert.visible('.repository-content', 'should repo detail visible');
browser.execute(function () {
return window.location;
}, function (args) {    // 确认打开了 nightwatch 官网
browser.assert.equal(args.value.pathname, '/nightwatchjs/nightwatch', 'should nightwatch repo found');
});
browser.end();
}
};
  运行测试
  · 运行 Selenium:java -jar selenium-server-standalone-3.0.0.jar
  · nightwatch test.js
  查看报告
  测试通过

  测试失败