【美高梅开户网址】可视化测试,测试你的前端代码

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

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

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

测试 App,你从哪儿伊始?在终极这几个部分,第6局地,Gil Tayar
计算了他为前端测试新人写的一而再串小说。最终那篇文章中,Tayar
讲述了可视化测试,以及为什么它是测试前端代码的末尾一步。

如今,小编八个恰好进入优质前端世界的爱侣打电话问小编该怎么测试他的应用程序。作者报告她有太多须求学习的事物,在电话里常有说不清楚。我承诺发送一些对她前端之路有所扶助的链接。

据此本人在电脑前坐下,通过 谷歌(Google)搜索相关的主旨。作者找到很多链接,也发送给她了,但自作者对这几个链接切磋的深浅并不合意。笔者找不到三个健全的指南
—— 以新入行的前端的角度 ——
指引怎样测试前端选择。小编没找到有个别指南既讲理论又讲实践,同时依然面向前端采纳的座谈。

之所以,小编决定写一个。那已经是这一多重的第5部分了。你可以在下边看看别的一些:

  • 介绍
  • 单元测试
  • 端到端(E2E)测试
  • 购并测试
  • 可视化测试

其它,为了写那篇小说,我写了三个小应用 ——
Calculator(计算器) ——
小编要用它以身作则测试的不等档次。你可以在此处看看它的源代码。

测试 App,你从哪儿起初?在结尾那个部分,第5部分,Gil Tayar
总计了他为前端测试新人写的多级小说。最终那篇文章中,Tayar
讲述了可视化测试,以及为啥它是测试前端代码的末梢一步。

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

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

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

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

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

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

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

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

可视化测试

软件测试一向是本人的一大爱好。近年来,小编觉着没有测试就写不出代码。对自家的话,有一种原始的想法,运转的目标就是为着证西楚码是还是不是科学。你的情趣是报告本人,在以前,每一次开发者修改他们的代码,都亟需有人手工去注脚从前日常的工作如故符合规律?是那般啊?

从而,作者写测试。因为小编爱不释手演说和写博客,我会解说或写关于软件测试的故事情节。如若有时机进入二个对提升软件测试有着卓绝远见的商行,写代码来扶持其旁人写测试,并拓宽她们的制品,小编会不假思索的出席。

正是如此,我近期出席了
Applitools
(如若你想了然职位,是布道师和高等架构师)。因为她们的成品,Applitools
Eyes,与本身写的这几个体系具有间接关联,我决定在这几个连串中多写贰个片段 ——
三个关于“可视化测试”的有的。

还记得本身的思疑呢?开发者实际总是会在每趟修改他们的代码之后运转他们的采用。嗯,到近期为止,软件出品要求手工测试
—— 那是在行使的可视化方面。还并未章程检查接纳看起来依旧是好的 ——
字体是毋庸置疑的,对齐没有失常态,颜色也还在,等等。

力排众议上你是可以写代码来进展连锁的自小编批评。我们在第2有的打听到哪些行使
Selenium Webdriver 测试 Web 应用的 UI。我们可以利用 Selenium 的
getScreenShot API
来获取页面的截图,将其保存为规范,之后每种测试都会将页面截图与那个条件举办比较:

美高梅开户网址 1

啊哈!如果如此不难就好了。小编尝试过那一个方案,结果遇上许多标题,最终只得扬弃那么些方案。而且可笑的是自身每一次修改了代码都要运转应用。首要的标题在有些技术:浏览器在显示内容的时候存在部分微薄的差别—— 造成那几个出入的要素大概源于屏幕或然GPU,对情节展开抗锯齿渲染的措施略有不相同。没有两张截图会拥有完全一致的像素。那么些差异人眼觉察不到,相当于说,按像素举办比较毫无意义。你须求运用图像分析技术来拍卖那一个标题。

而且,还有其它难题,仅从作者根据 Applitools 的干活就能统计出如下难点:

  • 您不可以对总体页面截图 —— 你只可以对可以见见的有个别截图。
  • 固然页面中设有动画,那就无法拿它和根基图像进行比较。
  • 动态数据,比如广告,会让事情变得复杂,难以找出与规范比较的实际差别。
  • 页面怎么时候才会“完全加载”?何时才能对其截图?未来在 DOM
    加载落成时截图是不够的。要找出怎么着时候才足以截图是件拾贰分不便的事情。

目前,作者一个正好进入优质前端世界的心上人打电话问作者该怎么测试他的应用程序。小编报告她有太多要求学习的事物,在机子里一直说不清楚。我承诺发送一些对她前端之路有所辅助的链接。

端到端测试

在其次有的中,大家采纳 Mocha
测试了利用中最主题的逻辑,calculator模块。本文中我们将使用端到端测试整个应用,实际上是效仿了用户拥有只怕的操作进行测试。

在大家的事例中,总结器显示出来的前端即为整个应用,因为从没后端。所以端到端测试就是说直接在浏览器中运转应用,通过键盘做一层层总结操作,且保障所显示的输出结果都以不易的。

是否要求像单元测试那样,测试各个组合呢?并不是,大家已经在单元测试中测试过了,端到端测试不是检查有些单元是不是ok,而是把它们放到一起,检查依旧否能够正确运营。

合龙测试

我们曾经看过了“测试光谱”中的二种测试:单元测试和端到端测试。实际工作中的测试平时是在乎那二种测试时期的,包含自作者在内的大部人一般把那种测试叫做集成测试。

我们做得到

可是大家似乎可以编写自动的可视化测试。存在着无数笔者并不知道的工具得以更好的截图并将之与正规图像比较。其中部分之类:

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

那几个工具得以消除全体或局地地方提到的难点。在多级的这么些部分,笔者想向你来得怎么样运用
Applitools Eyes 来编排可视化测试。

由此作者在电脑前坐下,通过 谷歌搜索相关的主旨。作者找到很多链接,也发送给她了,但本身对那么些链接探究的纵深并不令人满足。小编找不到八个周到的指南
—— 以新入行的前端的角度 ——
指导怎样测试前端接纳。小编没找到有些指南既讲理论又讲实践,同时仍旧面向前端采纳的座谈。

亟需有个别端到端测试

第贰付诸结论:端到端测试不要求太多。

首先个原因,假诺已经通过了单元测试和合并测试,那么可能早就把全数的模块都测试过了。那么端到端测试的效果就是把富有的单元测试绑到一起开展测试,所以不要求过多端到端测试。

第2个原因,那类测试一般都很慢。如果像单元测试那样有几百个端到端测试,那运转测试将会十三分慢,那就违反了多个很主要的测试原则——测试快捷报告结果。

其八个原因,端到端测试的结果有时候会油不过生
flaky的景观。Flaky
测试是指平时状态下得以测试通过,可是有时会出现测试战败的意况,约等于不平稳测试。单元测试大概不会冒出不安定的意况,因为单元测试平时是简约输入,不难输出。一旦测试涉及到了
I/O,那么不安静测试大概就涌出了。那可以收缩不安宁测试呢?答案是听之任之的,可以把不安定测试出现的频率减弱到可以承受的档次。那可以彻底消除不平静测试呢?大概可以,不过自个儿至今还没看出过[笑着哭]。

故而为了裁减大家测试中的不安宁因素,尽量裁减端到端测试。十三个以内的端到端测试,每种都测试应用的根本工作流。

关吴术语

和重重 TDD
爱好者聊过未来,我打听了她们对“集成测试”那几个词有一部分不相同的领会。他们认为集成测试是测试代码边界,即代码对外的接口部分。

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

而自作者和别的部分人则帮衬于认为“集成测试”是将多少个或多少个单元测试综合起来举办测试的一种办法。通过接口把与外部有关的代码打包到一起,再
mock,只是其中的一种完成格局。

自家的见地里,决定是不是拔取真实情状的 Ajax 或然其余 I/O
操作进行集成测试(即不选择mock),取决于是还是不是可以确保测试速度丰硕快,并且可以平安测试(不发出 flaky
的意况)。即便得以显然那样的话,那尽管用诚实风貌举行合并测试就好了。然则只要一点也不快恐怕暴发不安定测试的事态,那依然用
mock 会好一些。

在大家的事例中,计算器应用唯一的诚实 I/O 就是操作 DOM 了,没有 Ajax
调用,所以不设有上边的题材。

写一个可视化测试

既然如此可视化测试是测试的最后产品,它们应该用于端到端浏览器的前端测试中。所以那是自家的可视化测试。这么些代码格外幽默,它比正规的端到端测试更小。它由四个部分组成
—— 设置浏览器,测试 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())

那会打开2个浏览器并听候驱动命令。不过在开班测试以前,大家要求设置(以及拆迁)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(第6行),并开拓它们(第捌行)——
可爱的术语,不是吧?不要忘了从 Applitools 获取1个 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 =’)
})

与以此种类的前一篇文章中的端到端测试对照,你能够观望它很像,但更短。代码中要害的区分是对一定成分的证实被一行简单的代码代替了:

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 服务器的设置。

mock DOM

这就引出了三个题材:在合龙测试中是或不是须求 mock
DOM?重新考虑一下地点我说的标准,使用真实 DOM
是还是不是会使测试变慢呢,答案是会的。使用真实 DOM
意味着要用浏览器,用浏览器意味着测试速度变慢,测试变的不安宁。

那么是还是不是要么只好尽量把操作 DOM
的代码分离出来,要么只好动用端到端测试了啊?其实那两种方法都不佳。还有另一种缓解方案:jsdom。3个很是棒的包,用它本人的话说:那是在
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 钩子中开创3个 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
文件夹会同时选择在生养条件和端到端测试环境。这里要留心三个很关键的作业,端到端测试的运转条件要硬着头皮和生育环境保持一致。

歉意

这一某个是那些测试体系文章中唯一采纳钦命框架的一部分,那有的用到的框架是
React。拔取 React
并不是因为它是最好的框架,作者坚决地以为尚未所谓最好的框架,我居然觉得对于钦命的情状也绝非最好的框架。小编深信的是对此个人来讲,唯有最合适,用着最顺手的框架。

而我动用着最顺手的框架就是 React,所以接下去的代码都以 React
代码。不过此地依然说美素佳儿下,前端集成测试的 jsdom
解决方案可以适用于拥有的主流框架。

ok,将来回去正题。

运作可视化测试

大家怎么才行运维可视化测试更看到结果?

只要你未曾使用环境变量 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。

美高梅开户网址 2

那是因为还一向不用来比较的规范。另一方面,若是你看看 Applitools Eyes
界面,会看到:

美高梅开户网址 3

从 Applitools
来看,测试通过了,因为那是2个规格,它如果条件是不错的。你可以因此界面上逐个截图的“Like(像)/Unline(不像)”使其“失利”。

第一回运营 npm test,测试会成功:

美高梅开户网址 4

Applitools 界面也会显得为:

美高梅开户网址 5

如果大家有意让测试战败,(比如)通过点击 43 * 3 而不是 42 *
2,测试会战败,Applitools 界面会展现测试并高亮不相同之处:

美高梅开户网址 6

修补这几个“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。到近期终止,驱动部分就早已安装停止了。

使用 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
是三个浏览器变量,竟然可以采用在 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
      })

代码中开创了三个简短的 document,把大家的零部件挂在3个简便 div
上。同时还创制了1个 window,其实我们并不要求它,然而 React 须要。最后在
after 中清理全局变量。

documentwindow
一定要设置成全局的啊?滥用全局变量不论理论和施行的角度都不是个好习惯。要是它们是大局的,那这一个集成测试就不或许和任何的融会测试并行运营(那里对
ava
的用户表示对不起),因为它们会彼此覆写全局变量,导致结果错误。

只是,它们必须要设置成全局的,React 和 ReactDOM 须求 document
window 是全局的,不收受把她们以参数的花样传递。只怕等 React fiber
出来就可以了?大概吧,不过将来大家还必须求把 documentwindow
设置成全局的。

小结

那里对测试前端代码的一种类举办二个计算。假如您觉得自家遗漏了何等,恐怕有其它的题材/评论/吐槽,请推@giltayar,可能回应本文。

本身必须认可自个儿很想在那个序列中再多写一篇文章 —— 关于测试包罗 Ajax
调用的选择,实际的应用程序都会略微要求。

哪个人知道啊?

1 赞 2 收藏 1
评论

美高梅开户网址 8

端到端(E2E)测试

测试吧!

设置完驱动今后,该看一下测试的代码了。完整的测试代码在那边,上边列出部分代码:

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 行中与预期的标题举办相比。

那里还有四个题材,那里引入了 promise-retry
模块举办重试,为啥需求重试?原因是这么的,当大家告诉浏览器执行某吩咐,比如固定到一个U卡宴L,浏览器会去实施,不过是异步执行。浏览器执行的百般快,那时候对于开发人士来讲,确切地精通浏览器“正在履行”,要比但是知道三个结果更紧要。正是因为浏览器执行的不行快,所以一旦不重试的话,很简单被
await 所愚弄。在前边的测试中 promise-retry
也会经常利用,那就是怎么在端到端测试中须要重试的原由。

事件处理

剩余的测试代码怎么写吧,看上面代码:

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’)
    })
    //…

下3个要测试的是初叶化状态下所出示的是不是“0”,那么首先就必要找到控制显示的 element,在我们的例证中是
display。见第 7 行代码,webdriver 的 findElement
方法重回大家所要找的成分。可以透过 By.id或者 By.css
再或者其他找成分的形式。那里自身使用
By.css,它很常用,别的提一句 By.javascript 也很常用。

(不亮堂你是否注意到,By 是由最上边的 selenium-webdriver 所引入的)

当大家得到到了 element 未来,就足以运用 getText()(还是可以动用其他操作
element
的函数),来获取元素文本,并且检查它是不是和预期一样,见第九 行。对了,不要遗忘:

美高梅开户网址 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”。

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

运作测试

一度介绍完了端到端测试和单元测试,以往用 npm test 来运维具有测试:

美高梅开户网址 11

三遍性全体由此!(那是当然的了,不然怎么写小说。)

可视化测试

想说点有关使用 await 的某些话

您在大概网络上其他地点看到局地例子,它们并不曾动用
async/await,大概是选用了
promise。实际上那样的代码是一块的。那么为啥也能 work
的很好呢?坦白地说,作者也不了然,看起来像是在 webdriver 中稍加 trick
的处理。正如
selenium文档中说道,在
Node 资助 async/await 之前,那是3个临时的缓解方案。

Selenium
文档是 Java
语言。它还不完全,但是包含的新闻也丰裕了,你做四遍测试就能左右这些技能。

软件测试一向是自家的一大爱好。近来,作者觉得没有测试就写不出代码。对本人来说,有一种原始的想法,运转的目标就是为了印证代码是不是正确。你的意味是告诉小编,在之前,每趟开发者修改他们的代码,都要求有人手工去验证此前平常的作业依然寻常?是如此吧?

总结

正文中一言九鼎介绍了什么样:

  • 介绍了端到端测试中安装浏览器的代码;
  • 介绍了哪些使用 webdriver API 来调用浏览器,以及怎么样拿到 DOM 中的
    element;
  • 介绍了利用 async/await,因为有着 webdriver API 都以异步的;
  • 介绍了怎么端到端测试中要利用 retry。

    1 赞 收藏
    评论

美高梅开户网址 12

据此,作者写测试。因为自身喜欢演说和写博客,笔者会演说或写关于软件测试的始末。假使有机遇进入二个对增高软件测试有着一级远见的商号,写代码来救助其余人写测试,并加大她们的出品,小编会不暇思索的投入。

正是如此,作者目前加盟了 Applitools
(假使你想了然职位,是布道师和高级架构师)。因为他俩的成品,Applitools
Eyes,与自作者写的那么些连串具有直接关联,作者决定在这么些连串中多写一个部分 ——
二个关于“可视化测试”的局地。

还记得我的猜疑呢?开发者实际总是会在历次修改他们的代码之后运转他们的施用。嗯,到方今截至,软件出品必要手工测试
—— 那是在动用的可视化方面。还一直不艺术检查采纳看起来依旧是好的 ——
字体是不利的,对齐没不平常,颜色也还在,等等。

辩论上你是可以写代码来展开连锁的检查。大家在第一片段打听到什么拔取Selenium Webdriver 测试 Web 应用的 UI。我们得以采纳 Selenium 的
getScreenShot API
来博取页面的截图,将其保存为原则,之后各种测试都会将页面截图与这几个原则实行相比较:

啊哈!假使那般不难就好了。小编尝试过那些方案,结果遇上重重题材,最终只可以丢弃那一个方案。而且可笑的是本人老是修改了代码都要运维应用。首要的标题在一些技术:浏览器在突显内容的时候存在一些微小的差别—— 造成那一个出入的要素或者源于显示屏恐怕GPU,对故事情节展开抗锯齿渲染的章程略有不一样。没有两张截图会具有完全平等的像素。那几个差距人眼觉察不到,也等于说,按像素举办比较毫无意义。你必要运用图像分析技术来拍卖那一个标题。

并且,还有任何难点,仅从本人依照 Applitools 的劳作就能总计出如下难题:

你不可以对任何页面截图 —— 你不得不对能够见到的有的截图。

若是页面中留存动画,那就不或者拿它和基本功图像进行相比。

动态数据,比如广告,会让工作变得复杂,难以找出与原则相比较的实在差别。

页面怎么时候才会“完全加载”?哪天才能对其截图?今后在 DOM
加载达成时截图是不够的。要找出怎么着时候才方可截图是件万分不便的事体。

笔者们做得到

然则我们似乎可以编写自动的可视化测试。存在器重重本身并不知道的工具得以更好的截图并将之与正规图像相比。其中某些之类:

Wraith

WebdriverCSS

当然还有 Applitools Eyes

(如故其余的,但本文已经有点长了…)

那个工具得以缓解任何或部分地点提到的标题。在浩如烟海的那些局地,小编想向您出示如何使用
Applitools Eyes 来编排可视化测试。

写二个可视化测试

既然如此可视化测试是测试的最后产品,它们应该用于端到端浏览器的前端测试中。所以那是
我的可视化测试
。那一个代码分外有意思,它比不荒谬的端到端测试更小。它由多个部分组成 ——
设置浏览器,测试 Applitools Eyes 和测试本人。

大家再看一下 Selenium Driver 浏览器设置,它与 第3片段的端到端测试
相同:

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

那会打开2个浏览器并伺机驱动命令。不过在起头测试此前,大家须要安装(以及拆除)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(第⑤行),并开拓它们(第9行)——
可爱的术语,不是啊?不要忘了从 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
会截取页面图像并将之与前者测试产生的条件图像举办相比较(参阅上面的小节“运营可视化测试”)。要是比较结实是新图像与原则等价,则测试成功,否则测试失利。

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

进展可视化测试的远大利益是 —— 系统处理的一往直前。而且 ——
你不是只检查一五个因素 ——
你是在3次断言中检查整个页面。你或然会意识部分压根没想去找的题材!

看来,看起来可视化测试是端到端测试中绝无仅有的断言方法。但不幸的是,方今可视化断言较慢,所以你须求非凡地把部分检查一定成分的不荒谬断言和检查整个页面的可视化断言组合起来。

切记 ——
没有特效药妙药:没有某1个测试项目可以做有所业务!混合差别品种的测试可以更好的树立平衡,提出如此的纵横交错须要测试经验。所以未来就发轫测试!的确,测试须要时刻和任务。可是要是你从头测试,你就无法悔过自新了。

运维可视化测试

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

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

APPLITOOLS_APIKEY= npm test

尽管你采纳的是 Windows,那么:

set APPLITOOLS_APIKEY= && npm test

成功后就可以展开测试了。第1遍测试会战败并告知错误 EYES: NEW TEST
ENDED。

那是因为还一向不用来比较的准绳。另一方面,假设你看看 Applitools Eyes
界面,会看出:

从 Applitools
来看,测试通过了,因为那是一个原则,它一旦条件是毋庸置疑的。你可以因此界面上逐个截图的“Like(像)/Unline(不像)”使其“失败”。

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

Applitools 界面也会来得为:

假设大家有意让测试退步,(比如)通过点击 43 * 3 而不是 42 *
2,测试会失败,Applitools 界面会展现测试并高亮不一样之处:

修补那一个“Bug”必要在 Mocha 和 Applitools 中让测试再度通过。

小结

此间对测试前端代码的如拾草芥举办3个统计。即便您觉得自家遗漏了何等,只怕有其余的题材/评论/吐槽,请推
@giltayar ,只怕回应本文。

本身必须认可本人很想在那个种类中再多写一篇小说 —— 关于测试包蕴 Ajax
调用的采用,实际的应用程序都会稍微需求。

哪个人知道啊?

大家可以加一下作者的测试群:662354652 欢迎大家进群学习交换

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图