可视化测量检验,端到端测验
分类:前端技术

测试你的前端代码:可视化测试

2017/10/25 · CSS · 1 评论 · 测试

原文出处: Gil Tayar   译文出处:oschina   

测试 App,你从哪里开始?在最后这个部分,第五部分,Gil Tayar 总结了他为前端测试新人写的系列文章。最后这篇文章中,Tayar 讲述了可视化测试,以及为什么它是测试前端代码的最后一步。

不久前,我一个刚刚进入精彩前端世界的朋友打电话问我该怎么测试他的应用程序。我告诉她有太多需要学习的东西,在电话里根本说不清楚。我答应发送一些对她前端之路有所帮助的链接。

所以我在电脑前坐下,通过 Google 搜索相关的主题。我找到很多链接,也发送给她了,但我对这些链接讨论的深度并不满意。我找不到一个全面的指南 —— 以新入行的前端的角度 —— 指导如何测试前端应用。我没找到某个指南既讲理论又讲实践,同时还是面向前端应用的讨论。

因此,我决定写一个。这已经是这一系列的第五部分了。你可以在下面看到其它部分:

  • 介绍
  • 单元测试
  • 端到端(E2E)测试
  • 集成测试
  • 可视化测试

另外,为了写这篇文章,我写了一个小应用 —— Calculator(计算器) —— 我要用它演示测试的不同类型。你可以在这里看到它的源代码。

测试你的前端代码 – part3(端到端测试)

2017/06/05 · 基础技术 · 测试

原文出处: Gil Tayar   译文出处:胡子大哈   

上一篇文章《测试你的前端代码 – part2(单元测试)》中,我介绍了关于单元测试的基本知识,从本文介绍端到端测试(E2E 测试)。

  起初写博客是为了妹子学习,现在发现忽略了最基础的Selenium教程,所以:从本博客开始编辑 Selenium 入门知识。(学好Java)

可视化测试

软件测试一直是我的一大爱好。最近,我觉得没有测试就写不出代码。对我来说,有一种原始的想法,运行的目的就是为了验证代码是否正确。你的意思是告诉我,在以前,每次开发者修改他们的代码,都需要有人手工去验证之前正常的事情仍然正常?是这样吗?

因此,我写测试。因为我喜欢演讲和写博客,我会演讲或写关于软件测试的内容。如果有机会进入一个对加强软件测试有着卓越远见的公司,写代码来帮助其它人写测试,并推广他们的产品,我会毫不犹豫的加入。

正是如此,我最近加入了 Applitools (如果你想知道职位,是布道师和高级架构师)。因为他们的产品,Applitools Eyes,与我写的这个系列有着直接联系,我决定在这个系列中多写一个部分 —— 一个关于“可视化测试”的部分。

还记得我的疑惑吗?开发者实际总是会在每次修改他们的代码之后运行他们的应用。嗯,到目前为止,软件产品需要手工测试 —— 这是在应用的可视化方面。还没有办法检查应用看起来仍然是好的 —— 字体是正确的,对齐没有问题,颜色也还在,等等。

理论上你是可以写代码来进行相关的检查。我们在第三部分了解到如何使用 Selenium Webdriver 测试 Web 应用的 UI。我们可以使用 Selenium 的 getScreenShot API 来获得页面的截图,将其保存为基准,之后每个测试都会将页面截图与这个基准进行比较:

图片 1

啊哈!要是这么简单就好了。我尝试过这个方案,结果遇到不少问题,最后不得不放弃这个方案。而且可笑的是我每次修改了代码都要运行应用。主要的问题在某些技术:浏览器在呈现内容的时候存在一些细微的差异 —— 造成这些差异的因素可能来源于屏幕或者 GPU,对内容进行抗锯齿渲染的方式略有不同。没有两张截图会拥有完全一样的像素。这些差异人眼觉察不到,也就是说,按像素进行比较毫无意义。你需要使用图像分析技术来处理这个问题。

而且,还有其它问题,仅从我基于 Applitools 的工作就能总结出如下问题:

  • 你不能对整个页面截图 —— 你只能对可以看到的部分截图。
  • 如果页面中存在动画,那就不能拿它和基础图像进行比较。
  • 动态数据,比如广告,会让事情变得复杂,难以找出与基准相比的实际差异。
  • 页面什么时候才会“完全加载”?什么时候才能对其截图?现在在 DOM 加载完成时截图是不够的。要找出什么时候才可以截图是件非常困难的事情。

端到端测试

在第二部分中,我们使用 Mocha 测试了应用中最核心的逻辑,calculator模块。本文中我们将使用端到端测试整个应用,实际上是模拟了用户所有可能的操作进行测试。

在我们的例子中,计算器展示出来的前端即为整个应用,因为没有后端。所以端到端测试就是说直接在浏览器中运行应用,通过键盘做一系列计算操作,且保证所展示的输出结果都是正确的。

是否需要像单元测试那样,测试各种组合呢?并不是,我们已经在单元测试中测试过了,端到端测试不是检查某个单元是否 ok,而是把它们放到一起,检查还是否能够正确运行。

Selenium 入门 1:(学好Java)

我们做得到

不过我们似乎可以编写自动的可视化测试。存在着无数我并不知道的工具可以更好的截图并将之与标准图像比较。其中一些如下:

  • Wraith
  • WebdriverCSS
  • 当然还有 Applitools Eyes
  • (还是其它的,但本文已经有点长了…)

这些工具可以解决全部或部分上面提到的问题。在系列的这个部分,我想向你展示如何使用 Applitools Eyes 来编写可视化测试。

需要多少端到端测试

首先给出结论:端到端测试不需要太多。

第一个原因,如果已经通过了单元测试和集成测试,那么可能已经把所有的模块都测试过了。那么端到端测试的作用就是把所有的单元测试绑到一起进行测试,所以不需要很多端到端测试。

第二个原因,这类测试一般都很慢。如果像单元测试那样有几百个端到端测试,那运行测试将会非常慢,这就违背了一个很重要的测试原则——测试迅速反馈结果。

第三个原因,端到端测试的结果有时候会出现 flaky的情况。Flaky 测试是指通常情况下可以测试通过,但是偶尔会出现测试失败的情况,也就是不稳定测试。单元测试几乎不会出现不稳定的情况,因为单元测试通常是简单输入,简单输出。一旦测试涉及到了 I/O,那么不稳定测试可能就出现了。那可以减少不稳定测试吗?答案是肯定的,可以把不稳定测试出现的频率减少到可以接受的程度。那能够彻底消除不稳定测试吗?也许可以,但是我到现在还没见到过[笑着哭]。

所以为了减少我们测试中的不稳定因素,尽量减少端到端测试。10 个以内的端到端测试,每个都测试应用的主要工作流。

  录制回放,简单粗暴(如下图)。就不解释了。

写一个可视化测试

既然可视化测试是测试的最终产品,它们应该用于端到端浏览器的前端测试中。所以这是我的可视化测试。这个代码非常有意思,它比常规的端到端测试更小。它由三个部分组成 —— 设置浏览器,测试 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 会截取页面图像并将之与前端测试产生的基准图像进行比较(参阅下面的小节“运行可视化测试”)。如果比较结果是新图像与基准等价,则测试成功,否则测试失败。

写端到端测试代码

好了,废话不多说,开始介绍写端到端代码。首先需要准备好两件事情:1. 一个浏览器;2. 运行前端代码的服务器。

因为要使用 Mocha 进行端到端测试,就和之前单元测试一样,需要先对浏览器和 web 服务器进行一些配置。使用 Mocha 的 before 钩子设置初始化状态,使用 after钩子清理测试后状态。before 和 after 钩子分别在测试的开始和结束时运行。

下面一起来看下 web 服务器的设置。

图片 2

可视化测试是端到端测试更好的工具

进行可视化测试的巨大好处是 —— 系统处理的稳定性。而且 —— 你不是只检查一两个元素 —— 你是在一次断言中检查整个页面。你可能会发现一些压根没想去找的问题!

总的来说,看起来可视化测试是端到端测试中唯一的断言方法。但不幸的是,目前可视化断言较慢,所以你需要好好地把一些检查特定元素的常规断言和检查整个页面的可视化断言组合起来。

记住 —— 没有灵丹妙药:没有某一个测试类型可以做所有事情!混合不同类型的测试可以更好的建立平衡,建议这样的混合需要测试经验。所以现在就开始测试!的确,测试需要时间和责任。但是一旦你开始测试,你就不能回头了。

设置 Web 服务器

配置一个 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 文件夹会同时应用在生产环境和端到端测试环境。这里要注意一个很重要的事情,端到端测试的运行环境要尽量和生产环境保持一致。

 

运行可视化测试

我们怎么才行运行可视化测试更看到结果?

如果你没有使用环境变量 APPLITOOLS_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。

图片 3

这是因为还没有用于比较的基准。另一方面,如果你看看 Applitools Eyes 界面,会看到:

图片 4

从 Applitools 来看,测试通过了,因为这是一个基准,它假设基准是正确的。你可以通过界面上每个截图的“Like(像)/Unline(不像)”使其“失败”。

第二次运行 npm test,测试会成功:

图片 5

Applitools 界面也会显示为:

图片 6

如果我们故意让测试失败,(比如)通过点击 43 * 3 而不是 42 * 2,测试会失败,Applitools 界面会显示测试并高亮不同之处:

图片 7

修复这个“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 的版本)。

最后在测试函数中,传递网址:http:/localhost:8080,还是使用 await,让 driver.get 成为异步函数。

你是否有好奇 prepareDrivercleanupDriver 函数长什么样呢?一起来看下:

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。到现在为止,驱动部分就已经设置完毕了。

  Selenium 环境搭建(学好Java)

小结

这里对测试前端代码的系列进行一个总结。如果你觉得我遗漏了什么,或者有其它的问题/评论/吐槽,请推@giltayar,或者回应本文。

我必须承认自己很想在这个系列中再多写一篇文章 —— 关于测试包含 Ajax 调用的应用,实际的应用程序都会有些需要。

谁知道呢?

1 赞 2 收藏 1 评论

图片 8

测试吧!

设置完驱动以后,该看一下测试的代码了。完整的测试代码在这里,下面列出部分代码:

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 模块进行重试,为什么需要重试?原因是这样的,当我们告诉浏览器执行某命令,比如定位到一个 URL,浏览器会去执行,但是是异步执行。浏览器执行的非常快,这时候对于开发人员来讲,确切地知道浏览器“正在执行”,要比仅仅知道一个结果更重要。正是因为浏览器执行的非常快,所以如果不重试的话,很容易被 await 所愚弄。在后面的测试中 promise-retry 也会经常使用,这就是为什么在端到端测试中需要重试的原因。

Selenium是个 Java 的jar包,所以。必须要搭建好 Java 环境,既Path路径。例如下图

测试 Element

来看测试的下一阶段,测试元素:

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 行。对了,不要忘记:

图片 9

图片 10

测试 UI

现在该来从 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”。

然后 Selenium jar包导入 eclipse,方法很多。只讲最简单的,

运行测试

已经介绍完了端到端测试和单元测试,现在用 npm test 来运行所有测试:

图片 11

一次性全部通过!(这是当然的了,不然怎么写文章。)

图片 12

想说点关于使用 await 的一些话

你在可能网络上其他地方看到一些例子,它们并没有使用 async/await,或者是使用了 promise。实际上这样的代码是同步的。那么为什么也能 work 的很好呢?坦白地说,我也不知道,看起来像是在 webdriver 中有些 trick 的处理。正如 selenium文档中说道,在 Node 支持 async/await 之前,这是一个临时的解决方案。

Selenium 文档是 Java 语言。它还不完整,但是包含的信息也足够了,你做几次测试就能掌握这个技能。

环境搭建完毕。

总结

本文中主要介绍了什么:

  • 介绍了端到端测试中设置浏览器的代码;
  • 介绍了如何使用 webdriver API 来调用浏览器,以及如何获取 DOM 中的 element;
  • 介绍了使用 async/await,因为所有 webdriver API 都是异步的;
  • 介绍了为什么端到端测试中要使用 retry。

    1 赞 收藏 评论

图片 13

 

搭建好环境了,那么该怎么操作呢? 还记得怎么使用 hello word 么? 没错。

  举一反三。聪明的你,现在是不是只缺API了呢。

好的,搬运工开始了。

 

API(Selenium操作,纯粹搬运工)

然后就可以按照 Selenium 的API开始啦。

API 链接

 

1  用webdriver打开一个浏览器
    打开firefox浏览器:
            WebDriver driver = new FirefoxDriver();

    打开IE浏览器
            WebDriver driver = new InternetExplorerDriver ();

    打开chrome浏览器
       WebDriverdriver = new ChromeDriver();

1.2.2  最大化浏览器  
  WebDriver driver = new FirefoxDriver();
  driver.manage().window().maximize();

1.2.3 关闭浏览器 
WebDriver driver = new FirefoxDriver();
      driver.close();
      driver.quit();

1.3  打开测试页面
    driver.get("");
    driver.navigate().to("");
      P.S.navigate方法会产生1个Navigator对象,其封装了与导航相关的一些方法,比如前进后退等

1.4  页面元素定位
Webdriver提供下面两种方法来定位页面元素,参数是By对像,最常用是By.id和By.name查找。
    findElement   定位某个元素,如果没有找到元素会抛出异常:NoSuchElementException
    findElements     定位一组元素

 例如需要定位如下元素:
  <input class="input_class" type="text" name="passwd" id="passwd-id" />

    By.id:
      WebElement element = driver.findElement(By.id("passwd-id"));

    By.name:
      WebElement element = driver.findElement(By.name("passwd"));

    By.xpath:
      WebElement element =driver.findElement(By.xpath("//input[@id='passwd-id']"));

    By.className
      WebElement element = driver.findElement(By.className("input_class"));

    By.cssSelector
      WebElement element = driver.findElement(By.cssSelector(".input_class"));

    By.linkText:
      WebElement element = driver.findElement(By.linkText("百科"));

    By.partialLinkText:
      //这个方法就是模糊查询
      WebElement element = driver.findElement(By.partialLinkText("hao"));

    By.tagName:
      String test= driver.findElement(By.tagName("form")).getAttribute("name");

1.5  如何对页面元素进行操作
1.5.1 输入框(text field or textarea)
  WebElement element = driver.findElement(By.id("passwd-id"));
    element.sendKeys(“test”);//在输入框中输入内容:
    element.clear();       //将输入框清空
    element.getText();     //获取输入框的文本内容:

1.5.2下拉选择框(Select)
  Select select = new Select(driver.findElement(By.id("select"))); 
    select.selectByVisibleText(“A”);
    select.selectByValue(“1”);
    select.deselectAll();
    select.deselectByValue(“1”);
    select.deselectByVisibleText(“A”);
    select.getAllSelectedOptions();
    select.getFirstSelectedOption();

1.5.3单选项(Radio Button)
  WebElement radio=driver.findElement(By.id("BookMode"));
    radio.click();       //选择某个单选项
    radio.clear();      //清空某个单选项
    radio.isSelected();  //判断某个单选项是否已经被选择

1.5.4多选项(checkbox)
  WebElement checkbox = driver.findElement(By.id("myCheckbox."));
    checkbox.click();
    checkbox.clear();
    checkbox.isSelected();
    checkbox.isEnabled();

1.5.5按钮(button)
WebElement btn= driver.findElement(By.id("save"));
    btn.click();      //点击按钮
    btn.isEnabled ();  //判断按钮是否enable

1.5.7弹出对话框(Popup dialogs)
  Alert alert = driver.switchTo().alert();
    alert.accept();  //确定
    alert.dismiss();  //取消
    alert.getText(); //获取文本

1.5.8表单(Form)
  Form中的元素的操作和其它的元素操作一样,对元素操作完成后对表单的提交可以:
  WebElement approve = driver.findElement(By.id("approve"));
  approve.click();

  approve.submit();//只适合于表单的提交

1.5.9上传文件
  WebElement adFileUpload =driver.findElement(By.id("WAP-upload"));
  String filePath = "C:test\uploadfile\media_ads\test.jpg";
  adFileUpload.sendKeys(filePath);

1.6  Windows 和 Frames之间的切换
    driver.switchTo().defaultContent();     //返回到最顶层的frame/iframe
    driver.switchTo().frame("leftFrame");    //切换到某个frame:
    driver.switchTo().window("windowName"); //切换到某个window

1.7  调用Java Script
  JavascriptExecutor js = (JavascriptExecutor) driver;
        js.executeScript("JS脚本");

1.8  超时设置
        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);      //识别元素时的超时时间
        driver.manage().timeouts().pageLoadTimeout(10, TimeUnit.SECONDS);  //页面加载时的超时时间
        driver.manage().timeouts().setScriptTimeout(10, TimeUnit.SECONDS);  //异步脚本的超时时间

自由等待(隐形等待)

  new WebDriverWait(driver,10).until(ExpectedConditions.visibilityOfElementLocated(By.xpath(".//*[@id='btnAddEnlistAddorUpdate_relType']")));

 

最后,该怎么断言呢?

  断言就是用上面的 API给的 getxxx() 的方法,拿到实际值。然后断言是否等于case设定的预期。

最常用的是 element.getText(); 获取文本,判断文本内容。

  1. Assert.assertTrue(字符串.contains(预期));
  2. Assert.assertEquals(实际值 , 期望值);

By: Jack.Zhong

记得点赞哦

 

本文由pc28.am发布于前端技术,转载请注明出处:可视化测量检验,端到端测验

上一篇:HTML5正经的地点存款和储蓄,本地数据库 下一篇:没有了
猜你喜欢
热门排行
精彩图文