博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
从零开始做Vue前端架构(6)单元测试 & 代码覆盖率
阅读量:6373 次
发布时间:2019-06-23

本文共 8165 字,大约阅读时间需要 27 分钟。

新的一年(噗,都快年中了)

之前因为上家公司的经营出了问题,年前的大裁员,过了一个漫长的春节。 之后加入了新公司,然后正好赶上一个很紧急的项目,忙成狗,因此好久没更新文章了。 不过,我又回来啦!

原文

前言

自动化测试,我们将使用karma和nightmare,内容会包括:

  1. 单元测试
  2. e2e测试(放下一篇文章) 其实,单元测试一般用在写公共包的时候,比如通用的js函数库,通用的UI组件库。基本不太会在做业务项目的时候还使用单元测试。 然后,e2e测试的话,那其实往往是测试工程师需要做的,往往使用selenium。 那难道前端就不需要学测试了吗? 答案肯定是否定的,不然我写个毛...... vue的项目就用了单元测试和e2e。 基于vue的UI组件库,比如:饿了么的element、滴滴的cube-ui、有赞的vant等都有单元测试(咩有e2e,因为没必要)。 滴滴的话,我问了下黄轶大佬,他们项目前端自动化测试是用了单元测试和e2e的。 总之,两种都是由应用场景的,e2e虽然用的不多,或者说有时候不是前端自动化的范畴,但是其实做起来很简单,学会准没错!

一、单元测试

安装karma

npm install karma --save-devnpm install karma-jasmine karma-chrome-launcher jasmine-core --save-dev复制代码

package.jsonscripts配置 "test": "karma start"

初始化karma

$ karma init my.conf.jsWhich testing framework do you want to use?Press tab to list possible options. Enter to move to the next question.> mochaDo you want to use Require.js?This will add Require.js plugin.Press tab to list possible options. Enter to move to the next question.> noDo you want to capture a browser automatically?Press tab to list possible options. Enter empty string to move to the next question.> Chrome>What is the location of your source and test files?You can use glob patterns, eg. "js/*.js" or "test/**/*Spec.js".Press Enter to move to the next question.> test/**/*.js>Should any of the files included by the previous patterns be excluded?You can use glob patterns, eg. "**/*.swp".Press Enter to move to the next question.>Do you want Karma to watch all the files and run the tests on change?Press tab to list possible options.> yes复制代码

初始成功以后,会生成一份karma.conf.js配置文件。

顺便,在根目录创建一个test的文件夹,在这文件夹中创建一份index.js,内容为:

describe('A spec suite', function() {  it('contains a passing spec', function() {    console.log('Hello Karma')  })})复制代码

运行一下: npm run test 我们会看到程序会自动打开chrome浏览器,然后显示测试结果。

正式的写个单元测试

重新组织test文件夹

.└── unit    ├── index.js    ├── karma.conf.js    └── specs        └── dom.spec.js复制代码

因为我们还要做e2e测试,所以,在test下,用各个文件夹区分,unit下就是单元测试的内容了。

安装一系列包

karma-webpackkarma-sourcemap-loaderkarma-coveragechaisinonsinon-chaikarma-sinon-chaikarma-mocha-reporter复制代码

karma-webpack:因为我们的项目代码是用es6或者es7写的,所以webpack编译是必须的 karma-sourcemap-loader:sourcemap明显是必要的 karma-coverage:做代码覆盖率的时候需要用 chai:搭配mocha断言 sinon:搭配mocha做spy、stub、mock sinon-chai:用chai来做sinon的断言,可以说是扩展 karma-sinon-chai:方便在测试代码中的调用,直接就能用expect、sinon.spy等,不需要每个文件都import karma-mocha-reporter:mocha测试完的报告

像karma、mocha、chai、sinon这种测试工具,我不会很详细的介绍,全部都介绍的话内容实在有点多,而且也比较枯燥。想要学习可以看我的参考资料,是我花了大把时间筛选整理出来的。

修改karma.conf.js

const webpackConfig = require('../../webpack.config.test.js')module.exports = function(config) {  config.set({    // base path that will be used to resolve all patterns (eg. files, exclude)    basePath: '',    // frameworks to use    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter    frameworks: ['mocha', 'sinon-chai'],    // list of files / patterns to load in the browser    files: [      './index.js'    ],    // list of files / patterns to exclude    exclude: [    ],    // preprocess matching files before serving them to the browser    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor    preprocessors: {      './index.js': ['webpack', 'sourcemap', 'coverage']    },    // test results reporter to use    // possible values: 'dots', 'progress'    // available reporters: https://npmjs.org/browse/keyword/karma-reporter    reporters: ['mocha', 'coverage'],    coverageReporter: {      dir: './coverage',      reporters: [        { type: 'lcov', subdir: '.' },        { type: 'text-summary' }      ]    },    .    .    .    // Continuous Integration mode    // if true, Karma captures browsers, runs the tests and exits    singleRun: true,    // Concurrency level    // how many browser should be started simultaneous    concurrency: Infinity,    webpack: webpackConfig,    webpackMiddleware: {      stats: 'errors-only'    }  })}复制代码

karma原本在根目录,我们直接移过来就好了。然后修改的不多,我稍微解释一下:

  1. files:将要被测试的文件
  2. preprocessors:在引入文件前,需要用什么方式处理,我们看到了,包括webpack、sourcemap、coverage
  3. reporters:测试完成后的报告,我们需要mocha的报告和coverage的报告
  4. coverageReporter:代码覆盖率生成的报告文件地址和存在形式设置
  5. webpack:在这需要引入webpack的配置,我们见到顶部,引入了webpack.test.config.js文件,我们待会儿会介绍里面的配置
  6. webpackMiddleware:stats: 'errors-only'我们让webpack的编译过程不显示出来,除非编译报错

配置webpack.test.config.js

const webpackConfigBase = require('./webpack.config.base.js')const config = Object.assign(webpackConfigBase.config, {  // sourcemap 模式  devtool: '#inline-source-map',  module: {    rules: [      {        test: /\.js$/,        loader: 'babel-loader',        exclude: /node_modules/      }    ]  },})module.exports = config``#### 编辑index.js入口文件这个文件是为了配合`karma-webpack`的,详情见[Alternative Usage](https://github.com/webpack-contrib/karma-webpack#alternative-usage)```js// require all test files (files that ends with .spec.js)// 语法说明:https://doc.webpack-china.org/guides/dependency-management/#require-contextconst testsContext = require.context('./specs', true, /\.spec$/)testsContext.keys().forEach(testsContext)// require all src files which in the app/common/js for coverage.// you can also change this to match only the subset of files that// you want coverage for.const srcContext = require.context('../../app/common/js/', true, /\.js$/)srcContext.keys().forEach(srcContext)复制代码

测试代码放在./specs文件夹下,被测试原文件在../../app/common/js/下。这里我只测试一些公共的js文件,如果你需要测试其它,可自行修改。比如一些基于vue的UI组件库,你想要测试所有组件代码,还需要做些配置上的修改,这方面可以参考滴滴的cube-ui项目,挺完整的,覆盖率也很高。

正式写测试代码

编辑dom.spec.js文件:

/** * 测试common/utils/dom.js */import * as dom from 'common/js/utils/dom.js'// const expect = require('chai').expect 装过sinon-chai就不需要这句了;sinon同理describe('utils/dom', () => {  // 测试hasClass  it('hasClass', () => {    const ele = document.createElement('div')    ele.className = 'base kitty'    // 是否含有base    expect(dom.hasClass(ele, 'base')).to.be.equal(true)    // 是否含有kitty    expect(dom.hasClass(ele, 'kitty')).to.be.equal(true)    // 是否含有tom    expect(dom.hasClass(ele, 'tom')).to.be.equal(false)    // 无参数    expect(dom.hasClass()).to.be.equal(false)  })  // 测试addClass  it('addClass', () => {    const ele = document.createElement('div')    ele.className = 'base'    // 增加类名kitty    dom.addClass(ele, 'kitty')    expect(ele.className).to.be.equal('base kitty')    // 再增加类名kitty,希望并不会有重复类名    dom.addClass(ele, 'kitty')    expect(ele.className).to.be.equal('base kitty')  })  // 测试removeClass  it('removeClass', () => {    const ele = document.createElement('div')    ele.className = 'base kitty'    // 删除类名kitty    dom.removeClass(ele, 'kitty')    expect(ele.className).to.be.equal('base')    // 删除不存在的类名    dom.removeClass(ele, 'tom')    expect(ele.className).to.be.equal('base')  })  // 测试noce  it('once', () => {    const ele = document.createElement('div')    const callback = sinon.spy()    dom.once(ele, 'click', callback)    // 点击一次    ele.click()    expect(callback).to.have.been.calledOnce    // 再点击一次,预期应该是不调用callback的,所以依然为calledOnce    ele.click()    expect(callback).to.have.been.calledOnce  })})复制代码

代码注释已经很清楚啦~

运行测试

先修改下package.json配置:"test:unit": "karma start test/unit/karma.conf.js" 运行:

➜  construct git:(master) npm run test:unit> vue-construct@1.0.0 test:unit /Users/Terry/WFE/vue-study/construct> karma start test/unit/karma.conf.jsSTART:ℹ 「wdm」:ℹ 「wdm」: Compiled successfully.ℹ 「wdm」: Compiling...ℹ 「wdm」:ℹ 「wdm」: Compiled successfully.23 04 2018 01:25:39.438:INFO [karma]: Karma v2.0.0 server started at http://0.0.0.0:9876/23 04 2018 01:25:39.440:INFO [launcher]: Launching browser Chrome with unlimited concurrency23 04 2018 01:25:39.448:INFO [launcher]: Starting browser Chrome23 04 2018 01:25:41.778:INFO [Chrome 66.0.3359 (Mac OS X 10.13.2)]: Connected on socket A9ZeKTNtnUU9MAceAAAA with id 51610088  utils/dom    ✔ hasClass    ✔ addClass    ✔ removeClass    ✔ onceFinished in 0.008 secs / 0.004 secs @ 01:25:41 GMT+0800 (CST)SUMMARY:✔ 4 tests completed=============================== Coverage summary ===============================Statements   : 87.12% ( 142/163 ), 14 ignoredBranches     : 61.25% ( 49/80 ), 22 ignoredFunctions    : 86.11% ( 31/36 ), 5 ignoredLines        : 90.79% ( 138/152 )================================================================================复制代码

参考资料

论文是个很有意思的东西,看多了你会惊人地发现,很多大厂有深度的文章其实都是对论文的纯翻译~ 另外还参考了vue和滴滴的cube-ui的项目测试部分。

项目完整代码

转载地址:http://dknqa.baihongyu.com/

你可能感兴趣的文章
linux系统调用函数---12
查看>>
C#开发SQLServer的Geometry和Geography存储
查看>>
GPUImage API文档之GPUImageInput协议
查看>>
EBS R12.2应用层关闭脚本的执行过程
查看>>
js:深闭包(范围:上)
查看>>
使用POI导入小数变成浮点数异常
查看>>
Logistic Regression的几个变种
查看>>
PopupMenu消失(Dismiss)抓住
查看>>
Determining if a point lies on the interior of a polygon
查看>>
在 Angular 中实现搜索关键字高亮
查看>>
[Javascript ] Array methods in depth - sort
查看>>
司机福利!Uber即将可以自己选目的地接单啦!
查看>>
pycharm的注册(转载)
查看>>
MOGODB REDIS
查看>>
HDU 1231:最大连续子序列(DP)
查看>>
[java] java 中Unsafe类学习
查看>>
android 图片特效处理之图片叠加
查看>>
JAVA_SE基础——13.选择结构语句
查看>>
Ambari-stack介绍
查看>>
泛泰A870(高通APQ8064t 600 cpu) Mokee4.4.2(Android4.4) 图赏
查看>>