2017/10/25 · CSS · 1 评论 · 测试
原稿出处: Gil Tayar 译文出处:oschina
测量试验 App,你从哪里初阶?在结尾这一个某些,第五部分,Gil Tayar 总括了她为前端测验新人写的生机勃勃种类小说。最后那篇文章中,Tayar 叙述了可视化测量检验,以致为何它是测量检验前端代码的末尾一步。
前几天,作者三个适逢其会步向完美前端世界的相恋的人打电话问作者该怎么测验他的应用程序。小编报告她有太多必要上学的事物,在电话里根本说不清楚。笔者承诺发送一些对他前端之路有所支持的链接。
故此自身在Computer前坐下,通过 Google找寻相关的核心。小编找到相当多链接,也发送给她了,但自己对那些链接商量的吃水并不合意。作者找不到叁个康健的指南 —— 以新入行的前端的角度 —— 引导怎么样测验前端接纳。小编没找到某些指南既讲理论又讲实施,同不经常候依旧面向前端选拔的座谈。
进而,小编决定写贰个。那已然是那风度翩翩俯拾都已的第五某个了。你能够在上面看见其它一些:
其余,为了写那篇随笔,小编写了一个小应用 —— Calculator(计算器) —— 笔者要用它亲自去做测量试验的两样类型。你能够在这里地看看它的源代码。
2017/06/05 · 根基技能 · 测试
原作出处: Gil Tayar 译文出处:胡子大哈
上生龙活虎篇小说《测验你的前端代码 – part2(单元测验卡塔尔国》中,小编介绍了关于单元测量检验的基本知识,从本文介绍端到端测量试验(E2E 测量试验卡塔尔国。
Selenium2.0相助文书档案
软件测验平素是自己的一大爱好。近些日子,小编觉着未有测验就写不出代码。对本身的话,有风姿浪漫种原始的主张,运营的目标就是为着说古时候码是或不是准确。你的意思是报告笔者,在在此以前,每趟开采者修正他们的代码,都供给有人手工业去验证早先符合规律的事体仍旧寻常?是如此吧?
由此,笔者写测量试验。因为本身欣赏解说和写博客,我会演说或写关于软件测量试验的从头到尾的经过。假设有空子步入多个对加强软件测量检验有着精粹远见的公司,写代码来协理任何人写测量检验,并推广他们的付加物,作者会不假思索的步向。
便是如此,作者近年出席了 Applitools (如若你想知道职位,是布道师和高端架构师卡塔尔。因为她们的产物,Applitools Eyes,与自己写的那一个种类具备直接调换,作者说了算在此个体系中多写三个部分 —— 三个有关“可视化测量检验”的有个别。
还记得自个儿的纠结呢?开采者实际总是会在历次修正他们的代码之后运行他们的利用。嗯,到方今结束,软件出品必要手工业测量试验—— 那是在运用的可视化方面。还还没办法检查采用看起来依然是好的 —— 字体是正确的,对齐没不符合规律,颜色也还在,等等。
辩白上您是足以写代码来开展连锁的反省。我们在第四盘部叩问到如何行使 Selenium Webdriver 测量试验 Web 应用的 UI。大家能够使用 Selenium 的 getScreenShot API 来拿到页面包车型客车截图,将其保存为准则,之后各个测量试验都会将页面截图与那一个条件实行比较:
啊哈!若是那样轻巧就好了。小编尝试过这些方案,结果遇见相当多主题素材,最终只好废弃这么些方案。何况可笑的是小编老是改良了代码都要运营应用。主要的主题素材在一些工夫:浏览器在突显内容的时候存在有的微小的差别—— 变成那一个差异的成分恐怕出自显示器或然GPU,对剧情实行抗锯齿渲染的不二等秘书诀略有分裂。未有两张截图会怀有完全肖似的像素。那个差别人眼觉察不到,也正是说,按像素进行比较毫无意义。你需求运用图像剖判才干来拍卖那个标题。
还要,还会有任何难题,仅从自个儿依照 Applitools 的工作就能够总计出如下难点:
在第二片段中,大家应用 Mocha 测量试验了使用中最基本的逻辑,calculator模块。本文中大家将动用端到端测量检验整个应用,实际上是仿照了顾客全体希望的操作举行测量试验。
在大家的事例中,总计器展现出来的前端即为整个应用,因为从没后端。所以端到端测验正是说直接在浏览器中运作应用,通过键盘做一花样繁多总计操作,且保险所出示的出口结果都以对的的。
是否必要像单元测验那样,测量试验各样组合呢?并非,大家早就在单元测量检验中测量检验过了,端到端测量试验不是反省有个别单元是或不是ok,而是把它们放到一起,检查依旧否能够科学运维。
第1章 Webdirver基础 2
不过大家如同可以编写自动的可视化测验。存在着不菲我并不知道的工具得以更加好的截图并将之与正规图像相比较。个中风姿洒脱部分之类:
这几个工具得以减轻任何或一些地点提到的主题材料。在种类的那么些局地,笔者想向您出示怎样使用 Applitools Eyes 来编排可视化测量检验。
率先付诸结论:端到端测量检验没有必要太多。
先是个原因,如若已经因而了单元测量试验和购并测试,那么大概曾经把装有的模块都测量检验过了。那么端到端测量检验的法力正是把全体的单元测验绑到一齐张开测量检验,所以无需广大端到端测量试验。
其次个原因,那类测量试验平日都非常的慢。假设像单元测验那样有几百个端到端测量试验,这运转测量试验将会相当的慢,那就违背了一个很要紧的测验原则——测验急忙报告结果。
其两个原因,端到端测验的结果有的时候候会冒出 flaky的场合。Flaky 测量试验是指平时意况下能够测验通过,但是有的时候会并发测量检验退步的气象,相当于不平稳测量检验。单元测验差不离不汇合世不平静的景色,因为单元测量试验平常是简约输入,轻便输出。风流罗曼蒂克旦测量试验涉及到了 I/O,那么动荡测量试验恐怕就现身了。那能够减小不安宁测验呢?答案是一定的,能够把不平稳测量检验现身的成效减弱到能够接纳的程度。那能够通透到底消灭不平静测验呢?可能能够,不过本身到前些天还未看见过[笑着哭]。
由此为了减小大家测试中的不安静因素,尽量减少端到端测验。10个以内的端到端测验,种种都测量检验应用的关键专业流。
1.1 下载selenium2.0的lib包 2
既然如此可视化测验是测量试验的最终成品,它们应该用于端到端浏览器的前端测量试验中。所以那是自己的可视化测验。那几个代码特别常风趣,它比正规的端到端测验更加小。它由八个部分组成 —— 设置浏览器,测量试验 Applitools Eyes 和测量试验本人。
咱俩再看一下 Selenium Driver 浏览器设置,它与其三片段的端到端测量检验相同:
let driver before(async () => { driver = new webdriver.Builder().forBrowser('chrome').build() }) after(async () => await driver.quit())
1
2
3
4
5
6
|
let driver
before(async () => {
driver = new webdriver.Builder().forBrowser('chrome').build()
})
after(async () => await driver.quit())
|
那会展开贰个浏览器并伺机驱动命令。可是在起来测验之前,大家需求设置(甚至拆除与搬迁卡塔 尔(阿拉伯语:قطرApplitools Eyes:
const {Eyes} = require('eyes.selenium') let eyes before(async () => { eyes = new Eyes() eyes.setApiKey(process.env.APPLITOOLS_APIKEY) await eyes.open(driver, 'Calculator App', 'Tests', {width: 800, height: 600}) }) after(async () => await eyes.close())
1
2
3
4
5
6
7
8
9
10
11
|
const {Eyes} = require('eyes.selenium')
let eyes
before(async () => {
eyes = new Eyes()
eyes.setApiKey(process.env.APPLITOOLS_APIKEY)
await eyes.open(driver, 'Calculator App', 'Tests', {width: 800, height: 600})
})
after(async () => await eyes.close())
|
我们创造了部分新的 Eyes(第5行卡塔尔,并打开它们(第8行卡塔尔—— 可爱的术语,不是啊?不忘了从 Applitools 获取二个 API 的 Key,那是大家会在下一小节斟酌的事物,然后把它设置给 Eyes(第6行卡塔尔国。
现今大家曾经设置好浏览器和 Eyes,大家能够写测验了,那和我们的端到端测量试验特别像:
it('should look good', async function () { await driver.get('') await eyes.checkWindow('Initial Page') const digit4Element = await driver.findElement(By.css('.digit-4')) const digit2Element = await driver.findElement(By.css('.digit-2')) const operatorMultiply = await driver.findElement(By.css('.operator-multiply')) const operatorEquals = await driver.findElement(By.css('.operator-equals')) await digit4Element.click() await digit2Element.click() await operatorMultiply.click() await digit2Element.click() await operatorEquals.click() await eyes.checkWindow('After calculating 42 * 2 =') })
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
it('should look good', async function () {
await driver.get('http://localhost:8080')
await eyes.checkWindow('Initial Page')
const digit4Element = await driver.findElement(By.css('.digit-4'))
const digit2Element = await driver.findElement(By.css('.digit-2'))
const operatorMultiply = await driver.findElement(By.css('.operator-multiply'))
const operatorEquals = await driver.findElement(By.css('.operator-equals'))
await digit4Element.click()
await digit2Element.click()
await operatorMultiply.click()
await digit2Element.click()
await operatorEquals.click()
await eyes.checkWindow('After calculating 42 * 2 =')
})
|
与其大器晚成类别的前豆蔻梢头篇散文中的端到端测验对照,你能够见到它很像,但更加短。代码中至关心珍视要的界别是对一定成分的说明被风姿洒脱行简单的代码代替了:
await eyes.checkWindow(‘’)
1
|
await eyes.checkWindow(‘’)
|
在端到端测量检验中,大家是那样做的:
await retry(async () => { const displayElement = await driver.findElement(By.css('.display')) const displayText = await displayElement.getText() expect(displayText).to.equal('0') })
1
2
3
4
5
6
|
await retry(async () => {
const displayElement = await driver.findElement(By.css('.display'))
const displayText = await displayElement.getText()
expect(displayText).to.equal('0')
})
|
咱俩通过重试等待页面“牢固”。但进展可视化测量试验的时候,你不必要等待页面可以预知—— eyes.checkWindow 会帮你干这么些业务!
eyes.checkWindow 会截取页面图像并将之与前面三个测验产生的基准图像进行相比较(参阅上边包车型客车小节“运转可视化测验”卡塔 尔(英语:State of Qatar)。假诺相比较结实是新图像与规范等价,则测量试验成功,不然测量检验失利。
好了,废话非常的少说,伊始介绍写端到端代码。首先须要有备无患好两件事情:1. 三个浏览器;2. 运行前端代码的服务器。
因为要动用 Mocha 实行端到端测量检验,就和此前单元测量试验同样,须求先对浏览器和 web 服务器举办一些布置。使用 Mocha 的 before 钩子设置初步化状态,使用 after钩子清理测验后情形。before 和 after 钩子分别在测量检验的初始和了结时运营。
上边一齐来看下 web 服务器的设置。
1.2 用webdriver展开叁个浏览器 2
张开可视化测验的高大利益是 —— 系统处理的平静。并且 —— 你不是只检查大器晚成七个要素 —— 你是在三遍断言中反省整个页面。你或许会发觉有的压根没想去找的标题!
简单来说,看起来可视化测量检验是端到端测验中并世无双的预见方法。但不幸的是,方今可视化断言非常的慢,所以你要求赏心悦目地把一些反省一定成分的健康断言和检讨整个页面包车型地铁可视化断言组合起来。
牢牢记住 —— 没有特效药妙药:未有某八个测验项目能够做有所事情!混合分裂等级次序的测验能够越来越好的创造平衡,提议如此的混杂必要测量试检验资金历。所以未来就先导测验!的确,测量试验须要时刻和职务。可是意气风发旦你从头测量试验,你就不能够改弦更张了。
布局一个 Node Web 服务器,首先想到的就是 express了,话十分的少说,间接上代码:
JavaScript
let server before((done) = > { const app = express() app.use('/', express.static(path.resolve(__dirname, '../../dist'))) server = app.listen(8080, done) }) after(() = > { server.close() })
1
2
3
4
5
6
7
8
9
10
|
let server
before((done) = > {
const app = express()
app.use('/', express.static(path.resolve(__dirname, '../../dist')))
server = app.listen(8080, done)
})
after(() = > {
server.close()
})
|
代码中,before
钩子中创建四个 express 应用,指向 dist
文件夹,而且监听 8080 端口,停止的时候在 after
钩子中关闭服务器。
dist
文件夹是怎么样?是大家打包 JS 文件的地点(使用 Webpack打包卡塔尔,HTML
文件,CSS 文件也都在此边。可以看一下 package.json
的代码:
JavaScript
{ "name": "frontend-testing", "scripts": { "build": "webpack && cp public/* dist", "test": "mocha 'test/**/test-*.js' && eslint test lib", ... },
1
2
3
4
5
6
7
|
{
"name": "frontend-testing",
"scripts": {
"build": "webpack && cp public/* dist",
"test": "mocha 'test/**/test-*.js' && eslint test lib",
...
},
|
对于端到端测验,要记得在实施 npm test
之前,先执行
npm run build
。其实这么特别不便于,想转手事先的单元测量检验,无需做这么复杂的操作,正是因为它能够一向在
node 境况下运作,既不用转译,也不用包装。
鉴于完整性思谋,看一下 webpack.config.js
文件,它是用来报告 webpack
如何管理打包:
JavaScript
module.exports = { entry: './lib/app.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') }, ... }
1
2
3
4
5
6
7
8
|
module.exports = {
entry: './lib/app.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
...
}
|
上面的代码指的是,Webpack 会读取 app.js
文件,然后将 dist
文件夹中保有应用的公文都打包到 bundle.js
中。dist
文件夹会同期使用在生育蒙受和端到端测验情状。这里要在乎二个很要紧的职业,端到端测验的运作景况要硬着头皮和临盆条件保持豆蔻梢头致。
1.3 展开测验页面 2
笔者们怎么才行运维可视化测验更见到结果?
假定您从未利用意况变量 应用程式LITOOLS_APIKEY 来提供三个 API Key,npm test 就能够跳过可视化测验。所以需求拿到一个 API Key 来运转测量检验,去 Applitools 注册个客户就好。你能够在你的 Applitools 账户分界面找到 API Key。把它拷贝下来,用到测量试验中去(在 Linux/MacOS 中):
APPLITOOLS_APIKEY=<the-api-key> npm test
1
|
APPLITOOLS_APIKEY=<the-api-key> npm test
|
假若你采用的是 Windows,那么:
set APPLITOOLS_APIKEY=<the-api-key> && npm test
1
|
set APPLITOOLS_APIKEY=<the-api-key> && npm test
|
成功后就可以举行测验了。第二遍测量试验会退步并告诉错误 EYES: NEW TEST ENDED。
那是因为还没用来相比较的法规。其他方面,假使您看看 Applitools Eyes 分界面,会见到:
从 Applitools 来看,测量检验通过了,因为那是一个尺码,它大器晚成旦条件是合情合理的。你能够通过分界面上各类截图的“Like(像卡塔 尔(阿拉伯语:قطر/Unline(不像卡塔 尔(英语:State of Qatar)”使其“战败”。
第一回运转 npm test,测量检验会马到功成:
Applitools 分界面也交易会示为:
意气风发经大家有意让测验战败,(举例卡塔尔通过点击 43 * 3 而不是 42 * 2,测验会退步,Applitools 分界面会展现测验并高亮差别的地方:
修补这些“Bug”需求在 Mocha 和 Applitools 中让测量试验再次通过。
方今大家早就设置完了后端,应用已经有了服务器提供劳务了,今后要在浏览器中运作大家的计算器应用。用哪些包来驱动自动推行顺序吗,作者一时采用
selenium-webdriver
,那是三个相当火的包。
首先看一下什么样运用驱动:
JavaScript
const { prepareDriver, cleanupDriver } = require('../utils/browser-automation') //... describe('calculator app', function () { let driver ... before(async() = > { driver = await prepareDriver() }) after(() = > cleanupDriver(driver)) it('should work', async function () { await driver.get('') //... }) })
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
const {
prepareDriver, cleanupDriver
} = require('../utils/browser-automation')
//...
describe('calculator app', function () {
let driver
...
before(async() = > {
driver = await prepareDriver()
})
after(() = > cleanupDriver(driver))
it('should work', async
function () {
await driver.get('http://localhost:8080')
//...
})
})
|
before
中,筹算好驱动,在 after
中把它清理掉。策画好驱动后,会活动运维浏览器(Chrome,稍后会看见卡塔尔,清理掉未来会停业浏览器。这里注意,思量驱动的经过是异步的,重回一个promise,所以大家运用 async/await
成效来使代码看起来更巧妙(Node7.7,第三个地方帮助 async/await 的版本卡塔 尔(英语:State of Qatar)。
最终在测验函数中,传递网站:http:/localhost:8080
,还是使用 await,让
driver.get
成为异步函数。
你是还是不是有好奇 prepareDriver
和 cleanupDriver
函数长什么样呢?一同来看下:
JavaScript
const webdriver = require('selenium-webdriver') const chromeDriver = require('chromedriver') const path = require('path') const chromeDriverPathAddition = `: $ { path.dirname(chromeDriver.path) }` exports.prepareDriver = async() = > { process.on('beforeExit', () = > this.browser && this.browser.quit()) process.env.PATH = chromeDriverPathAddition return await new webdriver.Builder() .disableEnvironmentOverrides() .forBrowser('chrome') .setLoggingPrefs({ browser: 'ALL', driver: 'ALL' }) .build() } exports.cleanupDriver = async(driver) = > { if (driver) { driver.quit() } process.env.PATH = process.env.PATH.replace(chromeDriverPathAddition, '') }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
const webdriver = require('selenium-webdriver')
const chromeDriver = require('chromedriver')
const path = require('path')
const chromeDriverPathAddition = `: $ {
path.dirname(chromeDriver.path)
}`
exports.prepareDriver = async() = > {
process.on('beforeExit', () = > this.browser && this.browser.quit())
process.env.PATH = chromeDriverPathAddition
return await new webdriver.Builder()
.disableEnvironmentOverrides()
.forBrowser('chrome')
.setLoggingPrefs({
browser: 'ALL',
driver: 'ALL'
})
.build()
}
exports.cleanupDriver = async(driver) = > {
if (driver) {
driver.quit()
}
process.env.PATH = process.env.PATH.replace(chromeDriverPathAddition, '')
}
|
能够看出,下边这段代码很笨重,并且不能不在 Unix 系统上运维。理论上,你能够不用看懂,直接复制/粘贴到您的测量检验代码中就足以了,这里小编可能深远讲一下。
前两行引进了 webdriver 和我们选取的浏览器驱动 chromedriver。Selenium
Webdriver 的办事规律是透过 API(第风华正茂行中引入的
selenium-webdriver
卡塔 尔(阿拉伯语:قطر调用浏览器,那信任于被调浏览器的驱动。本例中被调浏览器驱动是
chromedriver
,在其次行引进。
chrome driver 没有需求在机器上装了 Chrome,实际上在您运转 npm install
的时候,已经装了它自带的可举办 Chrome 程序。接下来 chromedriver
的目录名供给增添进意况变量中,见代码中的第 9
行,在清理的时候再把它删掉,见代码中第 22 行。
设置了浏览器驱动今后,大家来安装 web driver,见代码的 11 – 15 行。因为
build
函数是异步的,所以它也利用
await
。到明天葬身鱼腹,驱动部分就早就设置完成了。
1.4 GettingStarted 2
此间对测量检验前端代码的无尽举办二个总括。若是你认为本身脱漏了怎么样,或许有任何的难题/研讨/作弄,请推@giltayar,大概回应本文。
小编必需承认本身很想在这里个种类中再多写生机勃勃篇小说 —— 关于测验包罗 Ajax 调用的使用,实际的应用程序都会微微要求。
哪个人知道吗?
1 赞 2 收藏 1 评论
安装完驱动现在,该看一下测量试验的代码了。完整的测量检验代码在那间,下边列出部分代码:
JavaScript
// ... const retry = require('promise-retry') // ... it('should work', async function () { await driver.get('') await retry(async() = > { const title = await driver.getTitle() expect(title).to.equal('Calculator') }) //...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
// ...
const retry = require('promise-retry')
// ...
it('should work', async
function () {
await driver.get('http://localhost:8080')
await retry(async() = > {
const title = await driver.getTitle()
expect(title).to.equal('Calculator')
})
//...
|
此间的代码调用总结器应用,检查接收标题是或不是 “Calculator”。代码中第 6
行,给浏览器赋地址:http://localhost:8080
,记得要运用 await
。再看第
9 行,调用浏览器况兼再次回到浏览器的标题,在第 10 行中与预期的标题实行比较。
这里还应该有二个难点,这里引进了 promise-retry
模块举行重试,为何须要重试?原因是这么的,当我们告诉浏览器试行某吩咐,举个例子固定到一个UWranglerL,浏览器会去实行,但是是异步试行。浏览器施行的要命快,那个时候对于开采人士来说,确切地领略浏览器“正在推行”,要比单独明白一个结实更关键。便是因为浏览器实行的不得了快,所以假如不重试的话,相当轻易被
await
所愚弄。在末端的测量试验中 promise-retry
也会平时使用,那正是为什么在端到端测量检验中需求重试的来头。
第2章 Webdirver对浏览器的援救4
来看测验的下风姿洒脱阶段,测量试验成分:
JavaScript
const { By } = require('selenium-webdriver') it('should work', async function () { await driver.get('') //... await retry(async() = > { const displayElement = await driver.findElement(By.css('.display')) const displayText = await displayElement.getText() expect(displayText).to.equal('0') }) //...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
const {
By
} = require('selenium-webdriver')
it('should work', async
function () {
await driver.get('http://localhost:8080')
//...
await retry(async() = > {
const displayElement = await driver.findElement(By.css('.display'))
const displayText = await displayElement.getText()
expect(displayText).to.equal('0')
})
//...
|
下三个要测量检验的是初叶化状态下所显示的是否“0”,那么首先就须求找到调控显示的 element,在大家的例子中是
display
。见第 7 行代码,webdriver 的 findElement
方法重回大家所要找的要素。能够透过 By.id
或者 By.css
再或者其余找成分的法门。这里本身使用
By.css
,它很常用,其它提一句 By.javascript
也很常用。
(不亮堂您是不是注意到,By
是由最上面包车型大巴 selenium-webdriver
所引入的卡塔 尔(阿拉伯语:قطر
当大家得到到了 element 以往,就能够运用 getText()
(仍然为能够动用别的操作
element
的函数卡塔尔国,来获得元素文本,並且检查它是否和预期同样,见第
10 行。对了,不要遗忘:
2.1 HtmlUnit Driver 4
几日前该来从 UI 层面测量检验应用了,点击数字和操作符,测量检验计算器是否坚决守住预期的周转:
JavaScript
const digit4Element = await driver.findElement(By.css('.digit-4')) const digit2Element = await driver.findElement(By.css('.digit-2')) const operatorMultiply = await driver.findElement(By.css('.operator-multiply')) const operatorEquals = await driver.findElement(By.css('.operator-equals')) await digit4Element.click() await digit2Element.click() await operatorMultiply.click() await digit2Element.click() await operatorEquals.click() await retry(async() = > { const displayElement = await driver.findElement(By.css('.display')) const displayText = await displayElement.getText() expect(displayText).to.equal('84') })
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
const digit4Element = await driver.findElement(By.css('.digit-4'))
const digit2Element = await driver.findElement(By.css('.digit-2'))
const operatorMultiply = await driver.findElement(By.css('.operator-multiply'))
const operatorEquals = await driver.findElement(By.css('.operator-equals'))
await digit4Element.click()
await digit2Element.click()
await operatorMultiply.click()
await digit2Element.click()
await operatorEquals.click()
await retry(async() = > {
const displayElement = await driver.findElement(By.css('.display'))
const displayText = await displayElement.getText()
expect(displayText).to.equal('84')
})
|
代码 2 – 4 行,定义数字和操作;6 – 10 行模拟点击。实际上想实现的是 “42 * 2 = ”。最后获得不错的结果——“84”。
2.2 FireFox Driver 4
曾经介绍完了端到端测量试验和单元测量检验,今后用 npm test
来运作具备测量试验:
一回性全体经过!(那是本来的了,不然怎么写小说。卡塔尔
2.3 InternetExplorer Driver 4
你在大概网络上别样地点看见一些例子,它们并从未动用
async/await
,或然是运用了
promise
。实际上那样的代码是一块的。那么为啥也能 work
的很好呢?坦白地说,作者也不知道,看起来疑似在 webdriver 中稍加 trick
的管理。正如
selenium文书档案中说道,在
Node 扶助 async/await
以前,那是二个一时半刻的施工方案。
Selenium 文档是 Java 语言。它还不完全,不过包涵的新闻也丰硕了,你做四次测量试验就能够左右那些手艺。
第3章 使用操作 4
本文中首要介绍了如何:
介绍了为啥端到端测验中要使用 retry。
1 赞 收藏 评论
3.1 怎么样找到页面成分4
3.1.1 By ID 5
3.1.2 By Name 5
3.1.3 By XPATH 5
3.1.4 By Class Name 5
3.1.5 By Link Text 5
3.2 怎么着对页面元素实行操作 6
3.2.1 输入框(text field or textarea) 6
3.2.2 下拉采摘框(Select) 6
3.2.3 单选项(Radio Button) 6
3.2.4 多选项(checkbox) 7
3.2.5 按钮(button) 7
3.2.6 左右筛选框 7
3.2.7 弹出对话框(Popup dialogs) 7
3.2.8 表单(Form) 8
3.2.9 上传文件 (Upload File) 8
3.2.10 Windows 和 Frames之间的切换 8
3.2.11 拖拉(Drag andDrop) 8
3.2.12 导航 (Navigationand History) 8
3.3 高等应用 9
3.3.1 改变user agent 9
3.3.2 读取Cookies 9
3.3.3 调用Java Script 9
3.3.4 Webdriver截图 10
3.3.5 页面等待 10
第4章 RemoteWebDriver 10
4.1 使用RemoteWebDriver 10
4.2 SeleniumServer 11
4.3 How to setFirefox profile using RemoteWebDriver 11
第5章 封装与录取 12
第6章 在selenium2.0中使用selenium1.0的API 14
http://code.google.com/p/selenium/downloads/list
官方UserGuide:http://seleniumhq.org/docs/
我们常用的浏览器有firefox和IE三种,firefox是selenium扶植得相比较早熟的浏览器。可是做页面包车型地铁测验,速度日常异常慢,严重影响不断集成的进程,这时提出利用HtmlUnit,可是HtmlUnitDirver运转时是看不到分界面包车型大巴,对调理就不方便人民群众了。使用哪类浏览器,能够做成配置项,根据必要灵活配置。
打开firefox浏览器:
//Create a newinstance of the Firefox driver
WebDriver driver = newFirefoxDriver();
打开IE浏览器
//Create a newinstance of the Internet Explorer driver
WebDriver driver = newInternetExplorerDriver ();
打开HtmlUnit浏览器
//Createa new instance of the Internet Explorer driver
WebDriverdriver = new HtmlUnitDriver();
对页直面测验,首先要开荒被测量检验页面包车型客车地方(如:http://www.google.com卡塔尔,web driver 提供的get方法可以展开贰个页面:
// And now use thedriver to visit Google
driver.get("");
package org.openqa.selenium.example;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait;
public class Selenium2Example {
public static voidmain(String[] args) {
// Create a newinstance of the Firefox driver
// Notice that theremainder of the code relies on the interface,
// not the implementation.
WebDriver driver = newFirefoxDriver();
// And now use this tovisit Google
driver.get("");
// Alternatively thesame thing can be done like this
// driver.navigate().to("");
// Find the text inputelement by its name
WebElement element =driver.findElement(By.name("q"));
// Enter something tosearch for
element.sendKeys("Cheese!");
// Now submit the form.WebDriver will find the form for us from the element
element.submit();
// Check the title ofthe page
System.out.println("Page title is: " driver.getTitle());
// Google's search isrendered dynamically with JavaScript.
// Wait for the pageto load, timeout after 10 seconds
(newWebDriverWait(driver, 10)).until(new ExpectedCondition<Boolean>() {
public Booleanapply(WebDriver d) {
returnd.getTitle().toLowerCase().startsWith("cheese!");
}
});
// Should see:"cheese! - Google Search"
System.out.println("Page title is: " driver.getTitle());
//Close the browser
driver.quit();
}
}
优点:HtmlUnit Driver不会实际展开浏览器,运营速度十分的快。对于用FireFox等浏览器来做测验的自动化测量检验用例,运维速度平时非常慢,HtmlUnit Driver无疑是能够很好地消除这一个主题素材。
破绽:它对JavaScript的支撑远远不够好,当页面上有复杂JavaScript时,日常会捕获不到页面成分。
使用:
WebDriver driver = new HtmlUnitDriver();
可取:FireFox Dirver对页面包车型地铁自动化测验扶持得相比较好,很直观地模仿页面包车型大巴操作,对JavaScript的支撑也不行完美,基本上页面上做的有所操作FireFox Driver都足以效仿。
破绽:运维异常的慢,运转也超级慢,但是,运维现在Webdriver的操作速度即使一点也不快但要么得以担任的,提出不用每每启动和停止FireFox Driver。
使用:
WebDriver driver = new FirefoxDriver();
Firefox profile的属性值是能够更改的,举例我们一向利用得十二分频仍的改观useragent的功能,能够这么校订:
FirefoxProfile profile = new FirefoxProfile();
profile.setPreference("general.useragent.override", "some UAstring");
WebDriver driver = new FirefoxDriver(profile);
亮点:直观地效法客户的实操,对JavaScript提供周全的支撑。
劣点:是兼具浏览器中运作速度最慢的,而且只好在Windows下运转,对CSS以至XPATH的支撑也远远不足好。
使用:
WebDriver driver = new InternetExplorerDriver();
Webdriver的findElement方法能够用来找到页面包车型地铁某个元素,最常用的办法是用id和name查找。上边介绍两种相比较常用的主意。
例如页面写成这么:
<input type="text" name="passwd"id="passwd-id" />
那就是说能够这么找到页面包车型客车成分:
通过id查找:
WebElement element = driver.findElement(By.id("passwd-id"));
或通过name查找:
WebElement element = driver.findElement(By.name("passwd"));
或通过xpath查找:
WebElement element =driver.findElement(By.xpath("//input[@id='passwd-id']"));
如若页面写成那样:
<div class="cheese"><span>Cheddar</span></div><divclass="cheese"><span>Gouda</span></div>
能够透过如此查找页面成分:
List<WebElement>cheeses = driver.findElements(By.className("cheese"));
倘诺页面成分写成这么:
<ahref=";
那么能够通过那样查找:
WebElement cheese =driver.findElement(By.linkText("cheese"));
找到页面成分后,怎么着对页面举行操作呢?大家得以依靠不相同的类别的成分来拓展依次表达。
找到输入框成分:
WebElement element = driver.findElement(By.id("passwd-id"));
在输入框中输入内容:
element.sendKeys(“test”);
将输入框清空:
element.clear();
获取输入框的文书内容:
element.getText();
找到下拉摘取框的要素:
Select select = new Select(driver.findElement(By.id("select")));
选用相应的选择项:
select.selectByVisibleText(“mediaAgencyA”);
或
select.selectByValue(“MA_ID_001”);
不接收相应的选择项:
select.deselectAll();
select.deselectByValue(“MA_ID_001”);
select.deselectByVisibleText(“mediaAgencyA”);
也许拿到接收项的值:
select.getAllSelectedOptions();
select.getFirstSelectedOption();
找到单选框成分:
WebElement bookMode =driver.findElement(By.id("BookMode"));
选取某些单选项:
bookMode.click();
清空某些单选项:
bookMode.clear();
推断有个别单选项是不是曾经被接收:
bookMode.isSelected();
多接收的操作和单选的差相当少:
WebElement checkbox =driver.findElement(By.id("myCheckbox."));
checkbox.click();
checkbox.clear();
checkbox.isSelected();
checkbox.isEnabled();
找到按键成分:
WebElement saveButton = driver.findElement(By.id("save"));
点击开关:
saveButton.click();
判断按钮是或不是enable:
saveButton.isEnabled ();
也正是左侧是可供选拔项,选拔后移动到左侧的框中,反之亦然。比如:
Select lang = new Select(driver.findElement(By.id("languages")));
lang.selectByVisibleText(“English”);
WebElement addLanguage =driver.findElement(By.id("addButton"));
addLanguage.click();
Alert alert = driver.switchTo().alert();
alert.accept();
alert.dismiss();
alert.getText();
Form中的成分的操作和此外的因素操作同样,对元素操作达成后对表单的提交可以:
WebElement approve = driver.findElement(By.id("approve"));
approve.click();
或
approve.submit();//只切合于表单的付出
上传文件的要素操作:
WebElement adFileUpload = driver.findElement(By.id("WAP-upload"));
String filePath = "C:test\uploadfile\media_ads\test.jpg";
adFileUpload.sendKeys(filePath);
诚如的话,登陆后提出是先:
driver.switchTo().defaultContent();
切换成有些frame:
driver.switchTo().frame("leftFrame");
从多个frame切换来另叁个frame:
driver.switchTo().frame("mainFrame");
切换成某些window:
driver.switchTo().window("windowName");
WebElement element =driver.findElement(By.name("source"));
WebElement target = driver.findElement(By.name("target"));
(new Actions(driver)).dragAndDrop(element, target).perform();
开拓三个新的页面:
driver.navigate().to("");
因而历史导航重回原页面:
driver.navigate().forward();
driver.navigate().back();
User Agent的装置是平日采纳得比较多的操作:
FirefoxProfile profile = new FirefoxProfile();
profile.addAdditionalPreference("general.useragent.override","some UA string");
WebDriver driver = new FirefoxDriver(profile);
咱俩平日要没错值举办读取和设置。
增加cookie:
// Now set the cookie. This one's valid for the entire domain
Cookie cookie = new Cookie("key", "value");
driver.manage().addCookie(cookie);
获取cookie的值:
// And now output all the available cookies for the current URL
Set<Cookie> allCookies = driver.manage().getCookies();
for (Cookie loadedCookie : allCookies) {
System.out.println(String.format("%s -> %s",loadedCookie.getName(), loadedCookie.getValue()));
}
基于有个别cookie的name获取cookie的值:
driver.manage().getCookieNamed("mmsid");
删除cookie:
// You can delete cookies in 3 ways
// By name
driver.manage().deleteCookieNamed("CookieName");
// By Cookie
driver.manage().deleteCookie(loadedCookie);
// Or all of them
driver.manage().deleteAllCookies();
Web driver对Java Script的调用是透过JavascriptExecutor来促成的,比方:
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("(function(){inventoryGridMgr.setTableFieldValue('" inventoryId "','" fieldName "','"
value "');})()");
如果用webdriver截图是:
driver = webdriver.Firefox()
driver.save_screenshot("C:error.jpg")
因为Load页面要求生龙活虎段时间,假诺页面尚未加载完就搜索成分,必然是寻找不到的。最佳的法门,正是安装一个暗许等待时间,在寻找页面元素的时候假使找不到就等候少年老成段时间再找,直到超时。
Webdriver提供二种办法,后生可畏种是显性等待,另生机勃勃种是隐性等待。
显性等待:
WebDriver driver =new FirefoxDriver();
driver.get("");
WebElement myDynamicElement = (new WebDriverWait(driver, 10))
.until(new ExpectedCondition<WebElement>(){
@Override
public WebElement apply(WebDriver d) {
returnd.findElement(By.id("myDynamicElement"));
}});
隐性等待:
WebDriver driver = new FirefoxDriver();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.get("");
WebElement myDynamicElement =driver.findElement(By.id("myDynamicElement"));
当本机上并未有浏览器,须要中远间隔调用浏览器进行自动化测量检验时,必要用到RemoteWebDirver.
import java.io.File;
import java.net.URL;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.remote.Augmenter;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
public class Testing {
public void myTest()throws Exception {
WebDriver driver = newRemoteWebDriver(
new URL(""),
DesiredCapabilities.firefox());
driver.get("");
// RemoteWebDriverdoes not implement the TakesScreenshot class
// if the driver doeshave the Capabilities to take a screenshot
// then Augmenter willadd the TakesScreenshot methods to the instance
WebDriveraugmentedDriver = new Augmenter().augment(driver);
File screenshot =((TakesScreenshot)augmentedDriver).
getScreenshotAs(OutputType.FILE);
}
}
在应用RemoteDriver时,必得在长间隔服务器运营八个SeleniumServer:
java -jar selenium-server-standalone-2.20.0.jar -port 4446
profile = new FirefoxProfile();
profile.setPreference("general.useragent.override",testData.getUserAgent());
capabilities = DesiredCapabilities.firefox();
capabilities.setCapability("firefox_profile", profile);
driver = new RemoteWebDriver(new URL(“);
driverWait = new WebDriverWait(driver,TestConstant.WAIT_ELEMENT_TO_LOAD);
driver.get("");
WebDriver对页面包车型大巴操作,需求找到叁个WebElement,然后再对其进行操作,对比麻烦:
// Find the text inputelement by its name
WebElement element = driver.findElement(By.name("q"));
// Enter something to search for
element.sendKeys("Cheese!");
咱俩得以虚构对那个骨干的操作实行三个装进,简化操作。比方,封装代码:
protected void sendKeys(By by, String value){
driver.findElement(by).sendKeys(value);
}
那么,在测验用例能够如此简化调用:
sendKeys(By.name("q"),”Cheese!”);
看,那就精短多了。
就像的包装还或许有:
package com.drutt.mm.end2end.actions;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.support.ui.WebDriverWait;
import com.drutt.mm.end2end.data.TestConstant;
public class WebDriverAction {
//protected WebDriverdriver;
protected RemoteWebDriverdriver;
protected WebDriverWaitdriverWait;
protected boolean isWebElementExist(By selector) {
try {
driver.findElement(selector);
return true;
} catch(NoSuchElementException e) {
return false;
}
}
protected StringgetWebText(By by) {
try {
return driver.findElement(by).getText();
} catch (NoSuchElementException e) {
return "Textnot existed!";
}
}
protected voidclickElementContainingText(By by, String text){
List<WebElement>elementList = driver.findElements(by);
for(WebElement e:elementList){
if(e.getText().contains(text)){
e.click();
break;
}
}
}
protected StringgetLinkUrlContainingText(By by, String text){
List<WebElement>subscribeButton = driver.findElements(by);
String url = null;
for(WebElement e:subscribeButton){
if(e.getText().contains(text)){
url =e.getAttribute("href");
break;
}
}
return url;
}
protected void click(Byby){
driver.findElement(by).click();
driver.manage().timeouts().implicitlyWait(TestConstant.WAIT_ELEMENT_TO_LOAD,TimeUnit.SECONDS);
}
protected StringgetLinkUrl(By by){
return driver.findElement(by).getAttribute("href");
}
protected void sendKeys(Byby, String value){
driver.findElement(by).sendKeys(value);
}
Selenium2.0中应用WeDriver API对页面实行操作,它最大的长处是无需设置八个selenium server就足以运作,然则对页面举行操作不及selenium1.0的Selenium RC API那么方便人民群众。Selenium2.0提供了采纳Selenium RC API的艺术:
// You may use any WebDriver implementation. Firefox is used hereas an example
WebDriver driver = new FirefoxDriver();
// A "base url", used by selenium to resolve relativeURLs
String baseUrl ="";
// Create the Selenium implementation
Selenium selenium = new WebDriverBackedSelenium(driver, baseUrl);
// Perform actions with selenium
selenium.open("");
selenium.type("name=q", "cheese");
selenium.click("name=btnG");
// Get the underlying WebDriver implementation back. This willrefer to the
// same WebDriver instance as the "driver" variableabove.
WebDriver driverInstance = ((WebDriverBackedSelenium)selenium).getUnderlyingWebDriver();
//Finally, close thebrowser. Call stop on the WebDriverBackedSelenium instance
//instead of callingdriver.quit(). Otherwise, the JVM will continue running after
//the browser has beenclosed.
selenium.stop();
自己分别采取WebDriver API和SeleniumRC API写了贰个Login的脚本,很扎眼,前面一个的操作尤其老妪能解。
WebDriver API写的Login脚本:
public void login() {
driver.switchTo().defaultContent();
driver.switchTo().frame("mainFrame");
WebElement eUsername= waitFindElement(By.id("username"));
eUsername.sendKeys(manager@ericsson.com);
WebElement ePassword= waitFindElement(By.id("password"));
ePassword.sendKeys(manager);
WebElementeLoginButton = waitFindElement(By.id("loginButton"));
eLoginButton.click();
}
SeleniumRC API写的Login脚本:
public void login() {
selenium.selectFrame("relative=top");
selenium.selectFrame("mainFrame");
selenium.type("username","manager@ericsson.com");
selenium.type("password","manager");
selenium.click("loginButton");
}
本文由星彩网app下载发布于前端技术,转载请注明出处:测试你的前端代码,0帮助文档