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

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

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

上一篇小说《测量检验你的前端代码 –
part2(单元测验)》中,笔者介绍了关于单元测量检验的基本知识,从本文介绍端到端测验(E2E
测量试验)。

端到端测量试验

在第二部分中,大家应用 Mocha
测量试验了选拔中最基本的逻辑,calculator模块。本文中我们将采取端到端测验整个应用,实际上是模拟了用户全体十分的大概率的操作举行测量试验。

在大家的例子中,计算器展现出来的前端即为整个应用,因为从没后端。所以端到端测量检验就是说直接在浏览器中运作应用,通过键盘做一名目好些个总括操作,且保险所出示的出口结果都以科学的。

是否需求像单元测量试验那样,测量检验各个组合呢?实际不是,我们早就在单元测量检验中测验过了,端到端测验不是反省某些单元是否ok,而是把它们放到一起,检查依然否能够准确运行。

须要多少端到端测量检验

率先付诸结论:端到端测验无需太多。

先是个原因,假如已经由此了单元测量检验和购并测量检验,那么也许曾经把具备的模块都测验过了。那么端到端测验的成效便是把具有的单元测量试验绑到一同张开测量检验,所以没有供给广大端到端测量检验。

其次个原因,那类测量试验一般都相当的慢。假使像单元测验那样有几百个端到端测量检验,这运转测量检验将会相当慢,这就违反了贰个很要紧的测量检验原则——测试飞快报告结果。

其五个原因,端到端测验的结果有的时候候会产出
flaky的情事。Flaky
测验是指平常情状下能够测量检验通过,可是一时晤面世测验退步的情况,也等于不安宁测量检验。单元测验差非常的少不会油可是生不平稳的景况,因为单元测量试验平日是简简单单输入,轻巧输出。一旦测量检验涉及到了
I/O,那么不稳固测验大概就应际而生了。这能够减小不安定测量试验呢?答案是必然的,能够把不安宁测量试验出现的作用裁减到勉强可以的等级次序。这能够透彻消除不稳固测量试验呢?大概能够,不过小编到最近还没来看过[笑着哭]。

由此为了削减我们测量试验中的不安宁因素,尽量收缩端到端测验。拾个以内的端到端测量检验,各个都测量检验应用的基本点专门的职业流。

凯旋门074网址,写端到端测验代码

好了,废话非常少说,初始介绍写端到端代码。首先要求预备好两件业务:1.
二个浏览器;2. 运作前端代码的服务器。

因为要使用 Mocha 进行端到端测量检验,就和前边单元测量试验同样,必要先对浏览器和
web 服务器举办一些布置。使用 Mocha 的
before 钩子设置初步化状态,使用
after钩子清理测量试验后状态。before 和 after
钩子分别在测量试验的开首和告竣作时间运维。

上面一同来看下 web 服务器的安装。

设置 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
文件夹会同不常间采用在生育条件和端到端测量试验境况。这里要注意八个很首要的事体,端到端测验的运转条件要硬着头皮和生育情形保持一致。

安装浏览器

当今我们已经安装完了后端,应用已经有了服务器提供服务了,未来要在浏览器中运作大家的计算器应用。用哪些包来驱动自动执行顺序吗,小编时时接纳
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 成为异步函数。

您是或不是有好奇 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。到现行反革命告竣,驱动部分就早已设置完结了。

测试吧!

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

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
模块举行重试,为何需求重试?原因是这么的,当大家告知浏览器试行某吩咐,譬喻固定到贰个U奥德赛L,浏览器会去试行,不过是异步试行。浏览器实行的异常快,那时候对于开采职员来说,确切地知道浏览器“正在实行”,要比唯有掌握一个结果更器重。正是因为浏览器试行的百般快,所以假使不重试的话,很轻松被
await 所愚弄。在末端的测验中 promise-retry
也会时临时接纳,这便是为什么在端到端测量试验中须要重试的因由。

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

澳门凯旋门注册网址 1

测试 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”。

运作测量检验

现已介绍完了端到端测量试验和单元测量检验,将来用 npm test 来运营具有测验:

澳门凯旋门注册网址 2

三次性全体经过!(这是自然的了,不然怎么写小说。)

想说点有关利用 await 的片段话

您在恐怕互连网上任哪个地方方看到有些例证,它们并从未使用
async/await,大概是应用了
promise。实际上那样的代码是一道的。那么为啥也能 work
的很好啊?坦白地说,笔者也不领悟,看起来疑似在 webdriver 中稍加 trick
的管理。正如
selenium文书档案中说道,在
Node 帮忙 async/await 在此以前,那是三个临时的缓慢解决方案。

Selenium
文档是 Java
语言。它还不完整,可是包括的音讯也丰裕了,你做五回测量检验就能够调控这些手艺。

总结

本文中要害介绍了怎么样:

  • 介绍了端到端测量检验中装置浏览器的代码;
  • 介绍了哪些接纳 webdriver API 来调用浏览器,以及怎么着得到 DOM 中的
    element;
  • 介绍了利用 async/await,因为有着 webdriver API 都是异步的;
  • 介绍了怎么端到端测量试验中要选拔 retry。

    1 赞 收藏
    评论

澳门凯旋门注册网址 3

相关文章