集成测试,测试你的前端代码

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

2017/06/05 · 基本功技术 ·
测试

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

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

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

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

初稿出处: Gil
Tayar   译文出处:oschina   

测试 App,你从什么地方开首?在结尾那个有个别,第肆有的,Gil Tayar
总括了她为前端测试新人写的触目皆是小说。最终那篇小说中,Tayar
讲述了可视化测试,以及为什么它是测试前端代码的最后一步。

近年来,笔者1个正好进入完美前端世界的爱侣打电话问笔者该怎么测试他的应用程序。作者报告她有太多要求上学的事物,在电话机里一贯说不清楚。小编承诺发送一些对她前端之路有所扶助的链接。

故而本人在电脑前坐下,通过 谷歌搜索相关的主旨。作者找到很多链接,也发送给她了,但自个儿对那些链接切磋的纵深并不乐意。俺找不到3个两全的指南
—— 以新入行的前端的角度 ——
率领怎么样测试前端拔取。我没找到有个别指南既讲理论又讲实践,同时依旧面向前端选用的座谈。

为此,小编控制写3个。这一度是这一多元的第六部分了。你可以在底下看看其余一些:

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

除此以外,为了写那篇作品,我写了一个小应用 ——
Calculator(计算器) ——
作者要用它以身作则测试的不等品种。你可以在此处看到它的源代码。

测试 App,你从哪里开头?在结尾这一个有个别,第⑤有个别,Gil Tayar
计算了他为前端测试新人写的连串小说。最终那篇文章中,Tayar
讲述了可视化测试,以及为何它是测试前端代码的最终一步。

测试你的前端代码 – part4(集成测试)

2017/06/05 · 基本功技术 ·
测试

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

上一篇小说《测试你的前端代码 –
part3(端到端测试)》集成测试,测试你的前端代码。中,小编介绍了关于端到端测试的基本知识,从本文介绍集成测试(Integration
Testing)。

端到端测试

在其次有个别中,大家选择 Mocha
测试了运用中最主旨的逻辑,calculator模块。本文中大家将应用端到端测试整个应用,实际上是模仿了用户拥有大概的操作进行测试。

在大家的事例中,统计器展现出来的前端即为整个应用,因为从没后端。所以端到端测试就是说直接在浏览器中运作应用,通过键盘做一密密麻麻计算操作,且保障所出示的输出结果都以毋庸置疑的。

是或不是要求像单元测试这样,测试种种组合呢?并不是,我们已经在单元测试中测试过了,端到端测试不是检查有个别单元是还是不是ok,而是把它们放到一起,检查如故否可以科学运营。

可视化测试

软件测试一直是自家的一大爱好。近期,小编觉得没有测试就写不出代码。对本人的话,有一种原始的想法,运营的目的就是为着验证代码是不是正确。你的意趣是报告小编,在原先,每便开发者修改他们的代码,都亟需有人手工去印证在此之前不荒谬的事务依旧平常?是如此吧?

为此,我写测试。因为自己喜爱解说和写博客,作者会演讲或写关于软件测试的内容。假设有时机进入贰个对增加软件测试有着杰出远见的公司,写代码来扶助其余人写测试,并拓宽她们的制品,我会不暇思索的参加。

正是如此,作者多年来加盟了
Applitools
(要是您想精通职位,是布道师和高级架构师)。因为她们的出品,Applitools
Eyes,与自身写的这几个连串具有间接交换,作者说了算在那么些体系中多写多个局部 ——
1个有关“可视化测试”的一部分。

还记得本身的迷惑呢?开发者实际总是会在历次修改他们的代码之后运维他们的采用。嗯,到近日甘休,软件出品须求手工测试
—— 那是在应用的可视化方面。还未曾章程检查选拔看起来仍然是好的 ——
字体是未可厚非的,对齐没非常,颜色也还在,等等。

辩驳上你是足以写代码来进展有关的检讨。大家在第③有的叩问到哪边行使
Selenium Webdriver 测试 Web 应用的 UI。大家可以采用 Selenium 的
getScreenShot API
来拿到页面的截图,将其保存为基准,之后每一种测试都会将页面截图与那个规格进行相比较:

亚洲必赢官网 1

啊哈!假诺那样不难就好了。作者尝试过这一个方案,结果遇见很多难题,最后不得不扬弃那么些方案。而且可笑的是本身每一遍修改了代码都要运营应用。首要的题材在好几技术:浏览器在表现内容的时候存在有的一线的差距—— 造成那么些差别的成分恐怕来自屏幕只怕GPU,对故事情节开展抗锯齿渲染的办法略有差距。没有两张截图会有着完全平等的像素。这几个差距人眼觉察不到,相当于说,按像素举行相比较毫无意义。你必要利用图像分析技术来拍卖那几个题材。

还要,还有其余难点,仅从自小编按照 Applitools 的办事就能总括出如下难题:

  • 您不能对整个页面截图 —— 你只好对可以看看的一些截图。
  • 只要页面中存在动画,那就无法拿它和底蕴图像举办比较。
  • 动态数据,比如广告,会让工作变得复杂,难以找出与规则相比较的实在差距。
  • 页面怎么时候才会“完全加载”?曾几何时才能对其截图?以往在 DOM
    加载落成时截图是不够的。要找出哪些时候才得以截图是件卓殊拮据的事务。

近来,我2个恰好进入完美前端世界的情人打电话问作者该怎么测试他的应用程序。作者告诉她有太多要求上学的东西,在电话机里平素说不清楚。我承诺发送一些对他前端之路有所帮助的链接。

集成测试

咱俩早就看过了“测试光谱”中的二种测试:单元测试和端到端测试。实际工作中的测试平日是在于那三种测试时期的,包罗自家在内的半数以上人平日把那种测试叫做集成测试。

亟需有个别端到端测试

首先付诸结论:端到端测试不需求太多。

先是个原因,假设已经经过了单元测试和集成测试,那么只怕曾经把持有的模块都测试过了。那么端到端测试的机能就是把装有的单元测试绑到一起展开测试,所以不须求广大端到端测试。

第②个原因,那类测试一般都很慢。假若像单元测试那样有几百个端到端测试,那运营测试将会非凡慢,那就违反了三个很首要的测试原则——测试快捷上报结果。

其多少个原因,端到端测试的结果有时候会冒出
flaky的场所。Flaky
测试是指寻常情形下可以测试通过,不过有时会产出测试失败的景观,约等于不安宁测试。单元测试大概不会油但是生不平稳的图景,因为单元测试常常是简单输入,不难输出。一旦测试涉嫌到了
I/O,那么不平静测试大概就现身了。那能够削减不安宁测试呢?答案是必定的,可以把不安定测试出现的频率收缩到能够承受的水平。那可以彻底化解不平静测试呢?可能可以,不过本身到前日还没看出过[笑着哭]。

于是为了减小我们测试中的不平稳因素,尽量减弱端到端测试。13个以内的端到端测试,逐个都测试应用的重大工作流。

我们做赢得

而是大家就像可以编制自动的可视化测试。存在着广大本人并不知道的工具得以更好的截图并将之与专业图像相比。其中有的之类:

  • Wraith
  • WebdriverCSS
  • 理所当然还有 Applitools
    Eyes
  • (依然其余的,但本文已经有点长了…)

这几个工具得以消除任何或一些地点提到的题材。在多样的这一个部分,作者想向您来得如何利用
Applitools Eyes 来编排可视化测试。

故而我在电脑前坐下,通过 Google搜索相关的主题。小编找到很多链接,也发送给她了,但本身对这个链接研究的吃水并不令人满意。作者找不到三个宏观的指南
—— 以新入行的前端的角度 ——
教导如何测试前端接纳。我没找到有些指南既讲理论又讲实践,同时如故面向前端选用的商讨。

至冬白术语

和无数 TDD
爱好者聊过现在,作者询问了他们对“集成测试”这一个词有一部分见仁见智的精晓。他们认为集成测试是测试代码边界,即代码对外的接口部分。

比如他们代码中有 Ajax,localStorage 或许 IndexedDB
操作,这其代码就不能做单元测试,那时他们会把那一个代码打包成接口,然后在做单元测试的时候
mock
那么些接口。当真正测试那一个接口的时候才称为“集成测试”。从那一个角度来说,“集成测试”就是在纯的单元测试以外,测试与表面“真实世界”相关的代码。

而自身和其他部分人则倾向于认为“集成测试”是将八个或多个单元测试综合起来举行测试的一种情势。通过接口把与表面有关的代码打包到联合,再
mock,只是其中的一种已毕形式。

小编的观点里,决定是还是不是选择真实场景的 Ajax 或然其余 I/O
操作进行合并测试(即不采取mock),取决于是不是能够有限帮忙测试速度丰硕快,并且可以安居乐业测试(不暴发 flaky
的状态)。要是得以分明那样的话,那尽管用诚实风貌举行合并测试就好了。不过只要很慢或然暴发不安宁测试的动静,那依旧用
mock 会好一些。

在大家的例子中,总结器应用唯一的真正 I/O 就是操作 DOM 了,没有 Ajax
调用,所以不设有上面的标题。

写端到端测试代码

好了,废话不多说,起首介绍写端到端代码。首先要求准备好两件业务:1.
二个浏览器;2. 运作前端代码的服务器。

因为要运用 Mocha 举行端到端测试,就和事先单元测试一样,要求先对浏览器和
web 服务器举办一些计划。使用 Mocha 的
before 钩子设置起头化状态,使用
after钩子清理测试后情形。before 和 after
钩子分别在测试的先河和了结时运转。

下边一起来看下 web 服务器的安装。

写一个可视化测试

既是可视化测试是测试的最终产品,它们应该用于端到端浏览器的前端测试中。所以那是本身的可视化测试。这几个代码非凡有意思,它比不荒谬的端到端测试更小。它由多少个部分组成
—— 设置浏览器,测试 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(第肆行),并打开它们(第捌行)——
可爱的术语,不是啊?不要忘了从 Applitools 获取二个 API 的
Key,那是大家会在下一小节研讨的事物,然后把它设置给 Eyes(第陆行)。

到现在我们曾经安装好浏览器和
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 =’)
})

与以此连串的前一篇作品中的端到端测试对照,你可以见见它很像,但更短。代码中第3的区分是对一定成分的辨证被一行简单的代码代替了:

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
会截取页面图像并将之与前者测试爆发的规则图像进行相比较(参阅上面的小节“运维可视化测试”)。要是相比较结实是新图像与标准等价,则测试成功,否则测试退步。

因而,作者控制写2个。那早已是这一连串的第四片段了。你可以在底下看看任何一些:

mock DOM

那就引出了三个标题:在合龙测试中是或不是需求 mock
DOM?重新思考一下上面我说的正统,使用真实 DOM
是不是会使测试变慢呢,答案是会的。使用真实 DOM
意味着要用浏览器,用浏览器意味着测试速度变慢,测试变的不平稳。

那么是或不是还是只好硬着头皮把操作 DOM
的代码分离出来,要么只好拔取端到端测试了呢?其实那三种办法都不佳。还有另一种缓解方案:jsdom。1个分外棒的包,用它自个儿的话说:那是在
NodeJS 中落到实处的 DOM。

它的确相比好用,能够运作在 Node 环境下。使用 JSDom,你可以不把 DOM 当做
I/O 操作。那点相当主要,因为要把 DOM
操作以前端代码中分离出来极度劳累(实际工作中大概不容许完全分离)。我猜
JSDom 的诞生就是因为这些原因:使得在 Node 中也足以运作前端测试。

咱俩来看一下它的劳作规律,和现在一致,需求有早先化代码和测试代码。本次大家先看测试代码。不过专业看代码在此以前请先接受小编的歉意。

设置 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
文件夹会同时利用在生养条件和端到端测试环境。那里要小心1个很重大的事体,端到端测试的周转条件要硬着头皮和生育环境保持一致。

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

进展可视化测试的宏伟好处是 —— 系统处理的安居乐业。而且 ——
你不是只检查一八个因素 ——
你是在五次断言中反省整个页面。你只怕会意识部分压根没想去找的题材!

看来,看起来可视化测试是端到端测试中唯一的断言方法。但不幸的是,方今可视化断言较慢,所以你必要出色地把一些反省一定成分的正规断言和检讨整个页面的可视化断言组合起来。

牢记 ——
没有特效药妙药:没有某1个测试项目可以做有所工作!混合不一致门类的测试可以更好的树立平衡,指出那样的叶影参差要求测试经验。所以今后就从头测试!的确,测试须要时间和职务。不过假使你起来测试,你就不只怕悔过自新了。

介绍

歉意

这一部分是这几个测试系列小说中绝无仅有选取钦点框架的一些,那部分运用的框架是
React。接纳 React
并不是因为它是最好的框架,我坚决地以为尚未所谓最好的框架,作者依然觉得对于内定的景观也从没最好的框架。作者相信的是对此个人来讲,唯有最合适,用着最顺手的框架。

而自小编动用着最顺手的框架就是 React,所以接下去的代码都是 React
代码。然而此地依旧说美素佳儿(Friso)(Meadjohnson)下,前端集成测试的 jsdom
消除方案得以适用于拥有的主流框架。

ok,现在回去正题。

设置浏览器

近来咱们已经安装完了后端,应用已经有了服务器提供劳动了,将来要在浏览器中运转大家的总括器应用。用什么样包来驱动自动执行顺序吗,作者时常应用
selenium-webdriver,那是三个很流行的包。

第3看一下怎么着利用驱动:

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(第3行中引入的
selenium-webdriver)调用浏览器,那着重于被调浏览器的驱动。本例中被调浏览器驱动是
chromedriver,在其次行引入。

chrome driver 不须求在机械上装了 Chrome,实际上在你运转 npm install
的时候,已经装了它自带的可实施 Chrome 程序。接下来 chromedriver
的目录名需求添加进环境变量中,见代码中的第 9
行,在清理的时候再把它删掉,见代码中第 22 行。

安装了浏览器驱动未来,大家来设置 web driver,见代码的 11 – 15 行。因为
build 函数是异步的,所以它也应用
await。到近年来达成,驱动部分就曾经安装已毕了。

运行可视化测试

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

若果您从未行使环境变量 APPLITOOLS_APIKEY 来提供3个 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。

亚洲必赢官网 2

那是因为还从未用来比较的规则。另一方面,倘若你看看 Applitools Eyes
界面,会看到:

亚洲必赢官网 3

从 Applitools
来看,测试通过了,因为那是一个规格,它假设条件是天经地义的。你可以因而界面上各种截图的“Like(像)/Unline(不像)”使其“失利”。

其次次运维 npm test,测试会成功:

亚洲必赢官网 4

Applitools 界面也会显得为:

亚洲必赢官网 5

假定大家有意让测试战败,(比如)通过点击 43 * 3 而不是 42 *
2,测试会失利,Applitools 界面会彰显测试并高亮不同之处:

亚洲必赢官网 6

修复那几个“Bug”需求在 Mocha 和 Applitools 中让测试再一次经过。

单元测试

使用 Jsdom

JavaScript

const React = require(‘react’) const e = React.createElement const
ReactDom = require(‘react-dom’) const CalculatorApp =
require(‘../../lib/calculator-app’) … describe(‘calculator app
component’, function () { … it(‘should work’, function () {
ReactDom.render(e(CalculatorApp), document.getElementById(‘container’))
const displayElement = document.querySelector(‘.display’)
expect(displayElement.textContent).to.equal(‘0’)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const React = require(‘react’)
const e = React.createElement
const ReactDom = require(‘react-dom’)
const CalculatorApp = require(‘../../lib/calculator-app’)
    …
describe(‘calculator app component’, function () {
        …
    it(‘should work’, function () {
        ReactDom.render(e(CalculatorApp), document.getElementById(‘container’))
        const displayElement = document.querySelector(‘.display’)
        expect(displayElement.textContent).to.equal(‘0’)

专注看第 10 – 14 行,首先 render 了 CalculatorApp 组件,那一个操作同时也
render 了 DisplayKeypad。第 12 和 14 行测试了 DOM
中总结器的显得是或不是是 0(初叶化状态下)。

上边的代码是可以运作在 Node 下的,注意到内部用的是
document。小编先是次利用它的时候特别愕然。全局变量 document
是3个浏览器变量,竟然可以应用在 NodeJS
中。在那简单的几行代码背后有着大量的代码支撑着,那么些 jsdom
代码大约是一揽子地落到实处了浏览器的法力。所以这边笔者要多谢 Domenic
Denicola, Elijah
Insua
和为以此工具包做过进献的人们。

亚洲必赢官网 7

第 10 行中也使用了 document(调用 ReactDom 来渲染组件),在 ReactDom
平时会使用它。那么在哪儿成立的这几个全局变量呢?在测试中开创的,见上面代码:

JavaScript

before(function () { global.document = jsdom(`<!doctype
html><html><body><div
id=”container”/></div></body></html>`)
global.window = document.defaultView }) after(function () { delete
global.window delete global.document })

1
2
3
4
5
6
7
8
9
before(function () {
        global.document = jsdom(`<!doctype html><html><body><div id="container"/></div></body></html>`)
        global.window = document.defaultView
      })
 
    after(function () {
        delete global.window
        delete global.document
      })

代码中开创了2个大致的 document,把大家的组件挂在3个简练 div
上。同时还创办了三个 window,其实大家并不须要它,不过 React 需求。最终在
after 中清理全局变量。

documentwindow
一定要设置成全局的吧?滥用全局变量不论理论和推行的角度都不是个好习惯。假诺它们是全局的,那这一个集成测试就不可以和任何的三合一测试并行运行(那里对
ava
的用户表示抱歉),因为它们会互相覆写全局变量,导致结果错误。

而是,它们必需要设置成全局的,React 和 ReactDOM 必要 document
window 是大局的,不收受把他们以参数的款型传递。恐怕等 React fiber
出来就足以了?或然吧,然而以后大家还必须求把 documentwindow
设置成全局的。

测试吧!

设置完驱动未来,该看一下测试的代码了。完整的测试代码在此处,下边列出部分代码:

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。再看第⑧ 行,调用浏览器并且再次来到浏览器的标题,在第 10 行中与预期的标题举行相比。

那里还有1个难点,那里引入了 promise-retry
模块进行重试,为何须要重试?原因是如此的,当大家告知浏览器执行某吩咐,比如固定到八个U奥迪Q5L,浏览器会去执行,可是是异步执行。浏览器执行的老大快,这时候对于开发人士来讲,确切地知道浏览器“正在举办”,要比仅仅知道二个结实更要紧。正是因为浏览器执行的可怜快,所以只要不重试的话,很简单被
await 所愚弄。在前面的测试中 promise-retry
也会不时利用,那就是怎么在端到端测试中要求重试的因由。

小结

此间对测试前端代码的文山会海进行3个统计。若是你以为本身遗漏了什么样,或然有其他的题材/评论/吐槽,请推@giltayar,可能回应本文。

本人无法不认同本人很想在这么些连串中再多写一篇作品 —— 关于测试包括 Ajax
调用的行使,实际的应用程序都会略带需求。

何人知道吧?

1 赞 2 收藏 1
评论

亚洲必赢官网 8

端到端(E2E)测试

事件处理

余下的测试代码怎么写吗,看上面代码:

JavaScript

ReactDom.render(e(CalculatorApp), document.getElementById(‘container’))
const displayElement = document.querySelector(‘.display’)
expect(displayElement.textContent).to.equal(‘0’) const digit4Element =
document.querySelector(‘.digit-4’) const digit2Element =
document.querySelector(‘.digit-2’) const operatorMultiply =
document.querySelector(‘.operator-multiply’) const operatorEquals =
document.querySelector(‘.operator-equals’) digit4Element.click()
digit2Element.click() operatorMultiply.click() digit2Element.click()
operatorEquals.click() expect(displayElement.textContent).to.equal(’84’)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
ReactDom.render(e(CalculatorApp), document.getElementById(‘container’))
const displayElement = document.querySelector(‘.display’)
expect(displayElement.textContent).to.equal(‘0’)
const digit4Element = document.querySelector(‘.digit-4’)
const digit2Element = document.querySelector(‘.digit-2’)
const operatorMultiply = document.querySelector(‘.operator-multiply’)
const operatorEquals = document.querySelector(‘.operator-equals’)
digit4Element.click()
digit2Element.click()
operatorMultiply.click()
digit2Element.click()
operatorEquals.click()
expect(displayElement.textContent).to.equal(’84’)

测试中任重先生而道远落成的是用户点击 “42 * 2 = ”,结果应当是出口 “84”。那里得到element 使用的是红得发紫的 querySelector 函数,然后调用 click
点击。还是能够创制事件,然后手动调度,见上边代码:

JavaScript

var ev = new Event(“keyup”, …); document.dispatchEvent(ev);

1
2
var ev = new Event("keyup", …);
document.dispatchEvent(ev);

此地有停放的 click 函数,所以大家一贯运用就好了。就是这般不难!

乖巧的你只怕早已发现了,那几个测试和前面的端到端测试事实上是相同的。不过注意那个测试要快
10 倍以上,并且实际它是一道的,代码也更便于写,可读性也更好。

不过只要都一律的话,那需求后续测试干嘛?因为那是个示范项目嘛,并不是实际项目。那一个类型里面唯有三个零件,所以端到端测试和继承测试是一样的。若是是在骨子里项目中,端到端测试可能含有了不少个单元,而接二连三测试只包涵少量单元,比如含有
拾个单元。所以实际上项目中唯有多少个端到端测试,而只怕包罗了广大个两次三番测试。

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

集成测试

总结

正文中主要介绍了怎么着:

  • 介绍了采用 jsdom
    方便地制造全局变量 documentwindow
  • 介绍了什么运用 jsdom 测试应用;
  • 介绍了,测试就是那样简单^_^。

    1 赞 收藏
    评论

亚洲必赢官网 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”。

可视化测试

运行测试

早就介绍完了端到端测试和单元测试,将来用 npm test 来运作具有测试:

亚洲必赢官网 11

三遍性全体经过!(那是本来的了,不然怎么写小说。)

其它,为了写那篇小说,作者写了一个小应用 —— Calculator(计算器) ——
我要用它以身作则测试的不比类型。你可以在此间看看它的源代码。

想说点有关采用 await 的有个别话

您在可能网络上其余地点看看部分例证,它们并没有行使
async/await,恐怕是使用了
promise。实际上那样的代码是一起的。那么为啥也能 work
的很可以吗?坦白地说,笔者也不理解,看起来像是在 webdriver 中稍微 trick
的拍卖。正如
selenium文档中协商,在
Node 帮助 async/await 在此以前,这是壹个暂且的消除方案。

Selenium
文档是 Java
语言。它还不完整,不过包括的新闻也丰裕了,你做三回测试就能理解这些技术。

可视化测试

总结

正文中主要介绍了何等:

  • 介绍了端到端测试中装置浏览器的代码;
  • 介绍了如何利用 webdriver API 来调用浏览器,以及如何获取 DOM 中的
    element;
  • 介绍了运用 async/await,因为具有 webdriver API 都以异步的;
  • 介绍了为啥端到端测试中要选用 retry。

    1 赞 收藏
    评论

亚洲必赢官网 12

软件测试平素是自己的一大爱好。近来,小编认为没有测试就写不出代码。对自作者来说,有一种原始的想法,运营的目标就是为了求证代码是不是科学。你的情致是告诉自个儿,在原先,每一趟开发者修改他们的代码,都急需有人手工去印证此前平常的事务照旧日常?是这般吗?

所以,作者写测试。因为自个儿欣赏演讲和写博客,我会演说或写关于软件测试的内容。即便有时机进来3个对压实软件测试有着超人远见的信用社,写代码来援救任何人写测试,并放大他们的产品,作者会不暇思索的加盟。

正是如此,小编多年来加入了 Applitools
(若是您想知道职位,是布道师和高级架构师)。因为他俩的成品,Applitools
Eyes,与自我写的那么些连串具有直接关联,作者决定在那几个系列中多写1个有的 ——
3个关于“可视化测试”的一些。

还记得本人的迷惑呢?开发者实际总是会在历次修改他们的代码之后运转他们的应用。嗯,到近来为止,软件出品要求手工测试
—— 这是在运用的可视化方面。还并未主意检查采纳看起来依旧是好的 ——
字体是不易的,对齐不荒谬,颜色也还在,等等。

辩护上您是足以写代码来进展相关的反省。我们在第贰有的打探到怎么样行使
Selenium Webdriver 测试 Web 应用的 UI。大家得以应用 Selenium 的
getScreenShot API
来得到页面的截图,将其保存为准绳,之后每一个测试都会将页面截图与那么些条件进行比较:

啊哈!假设那样不难就好了。小编尝试过那么些方案,结果遇上很多标题,最终只好放任这几个方案。而且可笑的是自身每一回修改了代码都要运转应用。主要的标题在一些技术:浏览器在呈现内容的时候存在部分分寸的差异—— 造成那个出入的要素只怕源于显示器大概GPU,对情节展开抗锯齿渲染的办法略有不一样。没有两张截图会有所完全相同的像素。那几个差距人眼觉察不到,也就是说,按像素进行相比毫无意义。你须求运用图像分析技术来处理那么些标题。

再者,还有任何难题,仅从自我依照 Applitools 的劳作就能统计出如下难点:

您不或者对全部页面截图 —— 你只好对可以看出的一部分截图。

设若页面中存在动画,那就无法拿它和根基图像举行比较。

动态数据,比如广告,会让事情变得复杂,难以找出与规范比较的实在差距。

页面怎么时候才会“完全加载”?曾几何时才能对其截图?将来在 DOM
加载已毕时截图是不够的。要找出如什么时候候才足以截图是件十三分不方便的政工。

大家做得到

但是我们就如可以编制自动的可视化测试。存在着累累小编并不知道的工具得以更好的截图并将之与正式图像相比。其中有的之类:

Wraith

WebdriverCSS

理所当然还有 Applitools Eyes

(依旧此外的,但本文已经有点长了…)

那个工具得以化解全数或局地地点提到的难题。在多元的那些部分,小编想向你来得怎样使用
Applitools Eyes 来编排可视化测试。

写贰个可视化测试

既然如此可视化测试是测试的最后产品,它们应该用于端到端浏览器的前端测试中。所以那是
小编的可视化测试
。这一个代码分外有趣,它比平常的端到端测试更小。它由多个部分组成 ——
设置浏览器,测试 Applitools Eyes 和测试自身。

小编们再看一下 Selenium Driver 浏览器设置,它与 第③局地的端到端测试
相同:

let driverbefore(async () => {driver = new
webdriver.Builder().forBrowser(‘chrome’).build()})after(async () =>
await driver.quit())

那会打开三个浏览器并等待驱动命令。然则在开班测试此前,大家需求设置(以及拆迁)Applitools
Eyes:

const {Eyes} = require(‘eyes.selenium’)let eyesbefore(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(第④行),并开拓它们(第柒行)——
可爱的术语,不是吗?不要忘了从 Applitools 获取壹个 API 的
Key,那是大家会在下一小节商量的东西,然后把它设置给 Eyes(第五行)。

今昔大家曾经设置好浏览器和
Eyes,大家可以写测试了,那和我们的端到端测试十分像:

it(‘should look good’, async function () { await
driver.get(‘ 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(‘’)

在端到端测试中,大家是这么做的:

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
会截取页面图像并将之与前者测试发生的条件图像进行相比(参阅上边的小节“运营可视化测试”)。假设相比结实是新图像与规范等价,则测试成功,否则测试失败。

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

开展可视化测试的铁汉利益是 —— 系统处理的安澜。而且 ——
你不是只检查一八个要素 ——
你是在五次断言中检查整个页面。你可能会发觉某些压根没想去找的题目!

如上所述,看起来可视化测试是端到端测试中绝无仅有的预感方法。但不幸的是,方今可视化断言较慢,所以你须求可以地把有些反省一定成分的平常化断言和反省整个页面的可视化断言组合起来。

难忘 ——
没有特效药妙药:没有某二个测试项目可以做有所事务!混合不同类其他测试能够更好的确立平衡,指出那样的交集须求测试经验。所以以后就开头测试!的确,测试必要时刻和权责。不过一旦您从头测试,你就无法悔过自新了。

运行可视化测试

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

若果你从未运用环境变量 APPLITOOLS_APIKEY 来提供二个 API Key,npm test
就会跳过可视化测试。所以要求得到3个 API Key 来运行测试,去 Applitools
注册个用户就好。你可以在你的 Applitools 账户界面找到 API
Key。把它拷贝下来,用到测试中去(在 Linux/MacOS 中):

APPLITOOLS_APIKEY= npm test

比方你利用的是 Windows,那么:

set APPLITOOLS_APIKEY= && npm test

成就后就足以开展测试了。第三遍测试会失败并报告错误 EYES: NEW TEST
ENDED。

那是因为还不曾用于比较的准绳。另一方面,倘使您看看 Applitools Eyes
界面,会看到:

从 Applitools
来看,测试通过了,因为那是三个准绳,它一旦条件是不易的。你能够透过界面上各类截图的“Like(像)/Unline(不像)”使其“失利”。

其次次运营 npm test,测试会马到功成:

Applitools 界面也会显得为:

设若大家有意让测试失利,(比如)通过点击 43 * 3 而不是 42 *
2,测试会战败,Applitools 界面会突显测试并高亮分化之处:

修补这些“Bug”须要在 Mocha 和 Applitools 中让测试再一次通过。

小结

此间对测试前端代码的文山会海进行二个计算。假使你觉得自个儿遗漏了怎么样,恐怕有任何的题材/评论/吐槽,请推
@giltayar ,可能回应本文。

自身不可以不认可本身很想在这么些连串中再多写一篇作品 —— 关于测试包涵 Ajax
调用的采用,实际的应用程序都会略微需求。

什么人知道啊?

我们能够加一下小编的测试群:662354652 欢迎大家进群学习互换

网站地图xml地图