首先要安装 Java 7 或更高 ,(http://www.oracle.com/technetwork/java/javase/downloads/index.html) 而且 java
命令可正常执行才能测试噢~~ 最简单的判断方法就是打开本身的终端,输入 java
并回车,看看是否是有 Java 运行。若是有命令不存在之类的提示,请从新安装 Java 运行环境 (javascript
Node.JS , 并且要确保 npm
命令可用,我想应该其实不用提醒的 ~
https://nodejs.org/en/download/html
咱们来找个地方新建一个目录,起名为 "my-test-toolkit",而后在目录内使用终端运行 npm init -y
生成项目配置文件package.json。java
而后咱们将安装 Selenium 与 Nightwatch。node
安装 selenium-standalone:git
npm install selenium-standalone --save-dev
github
安装 Nightwatch:web
npm install nightwatch --save-dev
chrome
咱们先开始配置 Nightwatch,以前提到这是一款 Test Runner 来着,它负责读取咱们的测试脚本,为咱们提供 API 来操做浏览器,帮咱们控制 Selenium。npm
一. 配置 Nightwatchjson
首先,在项目根目录创建文件 "nightwatch.json",这个文件用来存放 Nightwatch 的配置信息。建立完毕以后,在文件内写入如下内容:
{
"src_folders": ["tests"], "output_folder": "reports", "custom_commands_path": "", "custom_assertions_path": "", "page_objects_path": "", "globals_path": "", "selenium": { "start_process": true, "server_path": "", "log_path": "", "host": "127.0.0.1", "port": 4444, "cli_args": { "webdriver.chrome.driver": "" } }, "test_settings": { "default": { "launch_url": "http://localhost", "selenium_port": 4444, "selenium_host": "localhost", "silent": true, "screenshots": { "enabled": false, "path": "" }, "desiredCapabilities": { "browserName": "firefox", "javascriptEnabled": true, "acceptSslCerts": true } }, "chrome" : { "desiredCapabilities": { "browserName": "chrome", "javascriptEnabled": true, "acceptSslCerts": true } } } }
nightwatch.json 的文件名是 不能够 修改的,由于 Nightwatch 每次启动的时候都是从它读取配置喔!这里的配置项不少,不过先无论它,咱们接着建立文件。若是您但愿查看 Nightwatch 的详细配置,请点 这里。
接着在项目根目录下建立文件 "nightwatch.conf.js" ,一样此文件名也是不能够修改的,由于 Nightwatch 每次启动也会从它这里读取配置喔~ (´・_・`)
建立完毕后,打开文件,并写入以下内容:
const path = require('path') module.exports = (function (settings) { return settings; })(require('./nightwatch.json')) /* * Nightwatch 会从 nightwatch.json 中读取配置。 * 不过若是存在 nightwatch.conf.js,将会变为首先从后者中读取配置。 * nightwatch.conf.js 存在的意义是使用 JavaScript 动态生成配置信息。 * 若是配置信息是不须要代码修改的,直接使用 nightwatch.json 就能够啦。 */
再次在项目根目录创建文件 "startup.js",而后在文件内部写入:
require('nightwatch/bin/runner.js')
这个文件就是咱们测试的入口文件,之后咱们要执行测试就要运行这个文件,命令为 node ./startup
。入口文件的名字是能够按照喜爱更改的,只要运行它就好啦。不过每次输入 node ./startup
太麻烦了,因此咱们将这条命令写入 npm scripts 中 ~~~ 打开 "package.json",在 JSON 对象中创建 "script" 属性,并写入内容:
{
...
"scripts": { "start": "node ./startup.js" }, ... }
之后每次运行测试只要在项目根目录中执行 npm start
就行了!(・∀・)
Nightwatch 的配置暂时告一段落(其实立刻就会回来………),接下来咱们来处理 Selenium.
二. 配置 Selenium
Selenium 是自动化测试环境,它提供了测试服务器、启动浏览器、网页自动操做等功能,同时暴露 API 给 Nightwatch 供咱们使用。
咱们接下来将要告诉 Nightwatch 咱们的 Selenium 安装在哪里,启动浏览器的 Driver 程序在哪里,而后创建 Selenium 的安装脚本与手工启动脚本,以便不时之需 ~~
Driver 是让 Selenium 打开系统上已安装的浏览器的程序。
1. 创建 Selenium 的配置信息。
在项目根目录下创建文件夹 "build",并在其中建立文件 "selenium-conf.js",并写入以下信息:
const process = require('process')
module.exports = {
// Selenium 的版本配置信息。请在下方连接查询最新版本。升级版本只需修改版本号便可。 // https://selenium-release.storage.googleapis.com/index.html selenium: { version: '2.53.1', baseURL: 'https://selenium-release.storage.googleapis.com' }, // Driver 用来启动系统中安装的浏览器,Selenium 默认使用 Firefox,若是不须要使用其余浏览器,则不须要额外安装 Driver。 // 在此咱们安装 Chrome 的 driver 以便使用 Chrome 进行测试。 driver: { chrome: { // Chrome 浏览器启动 Driver,请在下方连接查询最新版本。 // https://chromedriver.storage.googleapis.com/index.html version: '2.22', arch: process.arch, baseURL: 'https://chromedriver.storage.googleapis.com' } } }
本配置信息包含 Selenium 本体配置与 Driver 配置。咱们将在稍后动态载入这些配置。 本文件的目的是为了更好管理 Selenium 的版本。
2. 告诉 Nightwatch,个人 Selenium 与 Driver 在哪里。
再次打开项目根目录下的 "nightwatch.conf.js" 文件,并这样编辑:
const seleniumConfig = require('./build/selenium-conf') const path = require('path') module.exports = (function (settings) { // 告诉 Nightwatch 个人 Selenium 在哪里。 settings.selenium.server_path = `${path.resolve()}/node_modules/selenium-standalone/.selenium/selenium-server/${seleniumConfig.selenium.version}-server.jar` // 设置 Chrome Driver, 让 Selenium 有打开 Chrome 浏览器的能力。 settings.selenium.cli_args['webdriver.chrome.driver'] = `${path.resolve()}/node_modules/selenium-standalone/.selenium/chromedriver/${seleniumConfig.driver.chrome.version}-${seleniumConfig.driver.chrome.arch}-chromedriver` return settings; })(require('./nightwatch.json'))
咱们新加了两行配置,它们的做用如注释所示。
一样的,若是您但愿查看更多的配置项,请点击 这里。
3. 创建 Selenium 安装脚本,一键安装 Selenium。
还记得上一章咱们提过 selenium-standalone 只是用来安装和管理 Selenium 的工具么?因此如今是时候用它来安装 Selenium 了。咱们将经过调取 selenium-standalone 的内置方法来实现自动安装。在 "build" 文件夹中创建文件 "selenium-setup.js",并写入以下信息:
const selenium = require('selenium-standalone') const seleniumConfig = require('./selenium-conf.js') selenium.install({ version: seleniumConfig.selenium.version, baseURL: seleniumConfig.selenium.baseURL, drivers: seleniumConfig.driver, logger: function (message) { console.log(message) }, progressCb: function (totalLength, progressLength, chunkLength) {} }, function (err) { if (err) throw new Error(`Selenium 安装错误: ${err}`) console.log('Selenium 安装完成.') })
一样为了方便,咱们将安装命令写入 npm scripts 中:
{
...
"scripts": { "start": "node ./startup.js", "selenium-setup": "node ./build/selenium-setup.js" }, ... }
而后在项目根目录执行 npm run selenium-setup
安装 Selenium.
当提示安装完成后,一切就绪!(・∀・)
Selenium 与其 Driver 会安装到 "node_modules/selenium-standalone/.selenium" 中。
4. 想要手工启动 Selenium?
默认状况下,Selenium 是由 Nightwatch 启动的,不须要手工干预,不过若是想要手工启动固然是能够的啦。
在 build 文件夹中创建文件 "selenium-start.js",并写入以下信息:
const selenium = require('selenium-standalone') const seleniumConfig = require('./selenium-conf.js') selenium.start({ drivers: seleniumConfig.driver }, function (err, child) { if (err) throw new Error(`Selenium 启动失败: ${err}`) console.log(`Selenium 已手工启动,进程 PID: ${child.pid}`) console.log('当再也不须要运行 Selenium 时可关闭此 PID 进程.') })
而后一样添加启动命令至 npm scripts 中:
{
...
"scripts": { "start": "node ./startup.js", "selenium-setup": "node ./build/selenium-setup.js", "selenium-start": "node ./build/selenium-start.js" }, ... }
之后使用命令 npm run selenium-start
就能够手工启动 Selenium 了。
至此,咱们的配置与安装工做已经完成,项目结构应该为:
>
| -- build | | -- selenium-conf.js # Selenium 版本信息配置。 | | -- selenium-setup.js # Selenium 安装命令脚本。 | | -- selenium-start.js # Selenium 启动命令脚本。 | | -- nightwatch.conf.js # Nightwatch 动态配置文件。 | -- nightwatch.json # Nightwatch 配置文件。 | -- package.json # 项目信息配置文件。 | -- startup.js # 测试启动入口文件。
“不过我好像看到 "nightwatch.json" 的配置很复杂,而咱们确没怎么动它?”
嗯~~ 到目前位置确实没有太多须要改动的,不过仍是要注意一个配置项:
请注意 "desiredCapabilities" 下的 "browserName" 项,这是测试时将使用的浏览器,您能够修改成 chrome
、internet explorer
、phantomjs
,本文在介绍时只安装了 Chrome 的 Driver,若是您须要使用其余浏览器,要安装相应的 Driver 才能够正常使用。
默认浏览器为 Firefox,若是您使用 Firefox 的话,不须要额外进行 Driver 的配置。
因此,若是您须要使用 Chrome 的话请将 "browserName" 修改成 "chrome" 喔!
Driver 的文档可参考这里。
若是您在搭建过程当中遇到困难,您能够从 Github 获取在下已经搭建好的 Start Kit.
开始编写测试用例
建立目录存放测试用例
在项目根目录新建一个名为 "tests" 的目录,而后这里就用来存放咱们即将编写的测试用例文件。
那么这个文件夹能不能指向到其余地方去呢?固然能够,不过要修改一个小地方。还记得 " nightwatch.json " 文件么?打开看看,第一项是否是叫
src_folders
,而后值为["tests"]
?
我相信您已经懂了,这里就是定义测试用例存放目录的地方,而后改为本身想要的目录吧!您能够在目录中存放多个测试用例文件,且命名随意,Nightwatch 将读取目录中全部的 JS 文件,若是符合测试用例格式,将会自动执行。
编写一个简单的测试用例
在 "tests" 目录中创建一个测试用例文件 "demo.js",而后咱们来写一个没什么用的小 demo!
这个 Demo 将打开 Bing,搜索 "what is microsoft",而后保存成截图后退出。
OK,打开 "demo.js",添加如下内容:
module.exports = { 'Find the answer.': function (client) { // TODO... } }
module.exports 导出一个对象,对象的 Key 即为测试用例名称,您能够编写多个测试用例,Nightwatch 将依次执行。
您能够在测试用例中导入其余模块并直接使用在测试逻辑中,这也是比 Phantom.JS 优秀的地方。
先写到这里,您可能会对
cilent
感到陌生,因此仍是要简单介绍一下。
client
是代码运行时 Nightwatch 提供的对象,全部对浏览器进行的操做都将使用此对象调取,好比client.click("CSS Selector")
、client.getCookie(function () {...})
,咱们第一章说过的 "能够简单理解为 Selenium 的控制软件" 就是经过它体现的喔!client 的全部 API 详情见 这里。
大体了解这东西的意思以后,就能够接着完善测试逻辑了:
module.exports = { 'Find the answer.': function (client) { // 定义 Bing 页面中的节点. const searchInput = '#sb_form_q' const searchBtn = '#sb_form_go' const question = 'what is microsoft' // 启动浏览器并打开 bing.com. client.url('http://bing.com').maximizeWindow() // 确保 "body" 和输入框可使用. client.expect.element('body').to.be.present client.expect.element(searchInput).to.be.visible client.pause(2000) // 稍等两秒. // 输入 "what is microsoft" 而后搜索. client.setValue(searchInput, question) client.click(searchBtn) client.pause(2000) // 截一张图而后保存到 "reports/answer.png". client.expect.element('body').to.be.present client.saveScreenshot('reports/answers.png') client.end() } }
来关注一下
expect
,是否是看起来很像天然语言?这些语句就是测试结果的验证语句,就是咱们但愿获得的结果。好比client.expect.element('body').to.be.present.before(3000)
,意思就是 "但愿 body 元素能在 3000 毫秒内初始化完毕"。Nightwatch 支持 BDD-Style 与 Assert 断言两种风格,文档可见 这里。
关于 Assert、BDD、TDD 的更多内容请参照其余文章。
是否是确实没什么用?毕竟是个简单的 Demo 而已,哈哈。那么添加一个稍微复杂点的测试用例。
编写另外一个简单的测试用例
这个 demo 将打开 Bilibili 直播 ,而后执行:
打开首页并等待加载完毕;
检查登录按钮是否存在;
点击登录按钮;
填写用户名与密码;
点击登录;
等待页面加载;
经过 Cookie 检查是否已登录;
确保登录后的用户导航面板存在;
鼠标移至头像处打开导航面板;
点击退出登录;
等待页面刷新后检查 Cookie 是否已退出登录;
结束测试。
其实就是第一章的那个 Demo 图干的事情了 (・∀・)这个 demo 再也不啰嗦,直接放出代码:
// Account setting. const accountConfig = { username: 'USERNAME', password: 'PASSWORD', uid: '10000' } module.exports = { 'Bilibili Live Login Test': function (client) { client.url('http://live.bilibili.com').maximizeWindow() // Page Init. client.expect.element('body').to.be.present.before(3000) client.expect.element('.top-nav-login-btn.last').to.be.visible // Login. client.click('.top-nav-login-btn.last') client.waitForElementVisible('#bilibili-quick-login', 2000) client.frame(0) client.pause(2000) client.setValue('#login-username', accountConfig.username) client.setValue('#login-passwd', accountConfig.password) client.click('#login-submit') // Wait and check page has been reloaded. client.frameParent() client.pause(4000) client.expect.element('body').to.be.present.before(3000) // Check cookies to ensure we are signed in. client.getCookies(function (result) { result.value.forEach((value, index, array) => { if (value.name === 'DedeUserID') client.assert.equal(parseInt(value.value, 10), accountConfig.uid) }) }) // Move to User Avatar. client.expect.element('.user-avatar-link').to.be.visible client.moveToElement('.user-avatar-link', 5, 5) client.pause(800) client.expect.element('#top-nav-user-panel').to.be.visible // Logout. client.click('#top-nav-logout-link') client.pause(5000) client.expect.element('body').to.be.present.before(3000) // Check cookies again to ensure we are off. client.getCookies(function (result) { var logout = true result.value.forEach((value, index, array) => { if (value.name === 'LIVE_LOGIN_DATA') logout = false }) client.assert.equal(logout, true) }) client.pause(1000) client.end() } }
您能够新建一个文件,或者在以前的文件中继续编写。
运行测试用例
回到项目根目录,执行
npm start
,而后就能够看到浏览器本身测试了!
运行效果以下:测试运行完毕以后,测试结果将打印在终端里,同时会生成到 reports 文件夹中。
您能够在 nightwatch.json 中修改 "output_folder" 来更换报告生成目录。
须要注意的地方
您可能在使用中会遇到例如 “明明看到节点缺获取不到”、“鼠标功能好像时好时坏” 等问题,在此给您一些建议:
因为如今不少网站使用诸如 Angular、Vue 等框架构建,其节点可能为组件动态渲染,因此 Selenium 在执行测试时可能获取的 Dom 树为旧数据从而致使找不到节点,所以您能够执行等待语句确保节点出现后再进行测试。不过可能不是 100% 成功,这也是这套测试系统的短板之一。
若是您在进行模拟鼠标的测试,您的鼠标指针可能会干扰您的测试,所以建议运行测试后将您的指针移动至屏幕外部,以免干扰到浏览器测试。
测试极可能由于页面加载时间问题致使测试失败,不过这也是 E2E 测试的特征所在,您能够修改您的测试逻辑,或致力缩短加载时间。
大功告成!
如今您已经拥有您本身的测试工具而且成功编写了两个测试用例!此处您应该为本身鼓掌!
您如今已经能够将 E2E 测试归入您的开发流程之中,在下相信这将对您的开发有不小的帮助。若是您有兴趣,您也能够考虑 单元测试的可能性。若是您没能成功构建您的项目,您能够从这里获取代码。
同时像以前提到的,若是您在使用 Vue 构建您的项目,您可使用 Vue-cli 来生成已经包含 Selenium 与 Nightwatch 的 Vue 种子项目,您能够在
test/e2e
中编写您的测试用例。