CodeLittlePrince / blog

A front-end blog | 前端博客
285 stars 30 forks source link

从零开始做Vue前端架构(7)e2e测试 #16

Open CodeLittlePrince opened 6 years ago

CodeLittlePrince commented 6 years ago

前言

吐槽

e2e测试在前端测试中,也许是最不被看重的一项吧。 小公司就不说了,即使是大厂,也极少有e2e测试。因为它需要花费的精力,相比得到的回报而言,可以说是相差悬殊,说白了,就是吃力不讨好- -|| e2e测试其实就是模拟用户行为,我们得根据业务写各种各样的不同操作。而几乎所有的项目,业务都是会变的。所以,因为业务变了,模拟用户行为也会随之改变。最后,就各种改,即改业务代码,又改测试代码,结果,无端端多出一大堆工作量,而且,很大的可能,下一轮迭代还得改,我上次就是这么死的。

燃鹅

但并不是所有的项目都不适合e2e测试的。比如,一个大项目,已经上线多年了,需求内容等基本都成形了。这种情况,就比较适合上e2e了。 项目大的缺点就是,修改的时候,一不小心就会牵一发而动全身。当年刚初来乍到的时候,就经常不小心改了公共样式,或者公共js,然后导致多个页面发生了变化,从而产生bug。因此,这种时候就很需要e2e测试了。

运用场景

总的来说,e2e的运用场景就是:上线久、业务稳、体量大的项目啦~(千万不要在刚启动或迭代很快的项目上e2e,切记,切记)

nightmare

nightmare是高阶浏览器自动测试库。

对比phantom

nightmare相比phantom而言,api更加简洁方便,比如引用的比较多的就是,同样是实现一个向yahoo自动提交关键词并搜索的功能:

  1. PhantomJS实现
    phantom.create(function (ph) {
    ph.createPage(function (page) {
    page.open('http://yahoo.com', function (status) {
      page.evaluate(function () {
        var el =
          document.querySelector('input[title="Search"]');
        el.value = 'github nightmare';
      }, function (result) {
        page.evaluate(function () {
          var el = document.querySelector('.searchsubmit');
          var event = document.createEvent('MouseEvent');
          event.initEvent('click', true, false);
          el.dispatchEvent(event);
        }, function (result) {
          ph.exit();
        });
      });
    });
    });
    });
  2. nightmare实现
    yield Nightmare()
    .goto('http://yahoo.com')
    .type('input[title="Search"]', 'github nightmare')
    .click('.searchsubmit');

    是不是感觉世界突然变得很美好?

工具

另外,官方文档还推荐了两个很棒的工具:

  1. niffy:UI diff工具
  2. daydream:这个就厉害了,chrome插件,我们可以直接在浏览器上操作,然后,它会生成对应的nightmare测试代码

配置

安装包

npm i -D nightmare

因为nightmare是基于electron的,安装的时候还会安装electron相关的东西,所以安装会比较慢,这个时候,可以打开网易云音乐来首歌。

牛刀小试

我们先用其他网站来做个小测试,比如github。 在test文件夹中,和unit文件夹同级,新建一个e2e文件夹,然后在e2e文件夹下新建一个叫test.js的文件,内容为:

const Nightmare = require('nightmare')
const chai = require('chai')
const expect = chai.expect

describe('test CodeLittlePrince results', () => {
  it('should find the CodeLittlePrince\'s blog github link first', function(done) {
    // 设定整个模拟的时长,超过则GG
    this.timeout('60s')

    const nightmare = Nightmare({
      show: true
    })

    nightmare
      .goto('https://github.com/login')
      .wait('input[name="login"]')
      .type('input[name="login"]', '1006312908@qq.com')
      .type('input[name="password"]', '******') // 用户名和密码自行修改
      .click('input[name="commit"]')
      .wait('input[placeholder="Search GitHub"]')
      .type('input[placeholder="Search GitHub"]', 'CodeLittlePrince/blog \u000d')
      .wait('a[href="/CodeLittlePrince/blog"]')
      .click('a[href="/CodeLittlePrince/blog"]')
      // .evaluate(() => document.querySelector('#links .result__a').href)
      // evaluate的作用就是将值return,给expect用
      .evaluate(() => location.href)
      .end()
      .then(link => {
        expect(link).to.equal('https://github.com/CodeLittlePrince/blog')
        done()
      })
  })
})

然后修改package.json的scripts:

"test:e2e": "mocha ./test/e2e/test.js"

最后运行看效果:

感觉棒棒的~

正式配置

因为运行过我的项目的同学知道,我只有三个页面,所以,可交互太少,所以我牛刀小试让同学们可以更加直观的感受到nightmare的方便。 接下来我们就来正式地配置吧。

文件组织

还是刚才的test/e2e文件夹下,删除text.js文件,创建index.js作为入口文件:

/**
 * e2e测试文件的入口文件
 */

// 测试页面的路由和文案是否正确
require('./specs/page.spec.js')

然后,创建specs文件夹,然后在该文件夹下创建文件page.spec.js:

const Nightmare = require('nightmare')
const chai = require('chai')
const expect = chai.expect
const nightmare = Nightmare({
  show: true 
})

describe('pages', () => {
  it('page ', function(done) {
    // 设定整个模拟的时长,超过则GG
    this.timeout('30s')
    nightmare
      .viewport(1200, 600)
      .goto('http://0.0.0.0:9999')
      .wait('h1')
      .click('a[href="#/pageA"]')
      .wait(() => {
        return location.hash === '#/pageA'
      })
      .click('a[href="#/pageB"]')
      .wait(() => {
        return location.hash === '#/pageB'
      })
      .evaluate(() => location.hash)
      .end()
      .then(hash => {
        expect(hash).to.equal('#/pageB')
        done()
      })
  })
})

修改下package.json的scripts:

"test:e2e": "mocha ./test/e2e/index.js"

运行

  1. 先运行:npm run dev
  2. 再运行:npm run test:e2e

结果

➜  construct git:(master) ✗ npm run test:e2e

> vue-construct@1.0.0 test:e2e /Users/Terry/WFE/vue-study/construct
> mocha ./test/e2e/index.js

  pages
    ✓ page  (1431ms)

  1 passing (1s)

评价

感觉测试流程,这样有点鸡肋,因为得先run dev,说不定有需要还需要run mock,最后再run test:e2e,略繁琐。当然,这些都可以被优化成一步。 不过,个人感觉,e2e在联调以后,进入开发环境,或者测试环境以后测也可以。或者说,在测试环境测就好了,测试环境和线上环境比较接近,效果更好。本身e2e测试就是测试开发工程师写的,所以,在测试环境测也合理。不然,本地要测一遍,开发环境又测,测试环境又测,多累呐。 最后,也希望各位有什么好的意见或者建议,可以在评论区留言,讨论讨论呐~

预告

有同学反应我的vue项目没有加入vuex,额,好吧,下一篇我们加一下vuex,也出一篇文章,以免我自己偷偷加,发生断片,让同学们迷糊。 再之后呢,我们就会把这个项目利用yeoman做成脚手架啦!

CodeLittlePrince commented 6 years ago

e2e参考项目实在是太少,也希望大家能够推荐一些文章或者项目,谢谢啦!