前言:本文用于2018/1/30晚内部分享。
主题:前端单元测试
正文:
一、思考
我的目标是,如何浅入本次的主题,让愿意接收陌生信号的“对象”快速简单的get到信号,并且对本次分享产生一个小兴趣。
二、What
本章节主要讲述前端单元测试做什么,vue单元测试做什么。
(1) 基础概念
- 测试的概念:测试是检测你的应用代码(也叫“生产代码”)是否按预期执行的过程。测试可以手动测试,也可用自动测试(用编写好的代码代替人工做检测的工作),本文主要围绕后者展开。
- 测试的分类:测试按照不同标准分类很多,不属于同一次元不能作比较。前端测试根据测试范围分类主要分为单元测试和端到端测试(E2E测试)。
(2) 前端单元测试(Unit Test)
- 前端单元测试:是以单元为单位进行的测试。
- 单元:可以是一个函数、一个模块、一个包或者一个类,甚至是一个对象,在不同编程语言中定义不一样。
- 为什么需要单元测试:使代码健壮,质量高(减少 QA 测试报告的反馈),兼容各种临界点,保证代码的整洁清晰。通俗的说,就是降低返工率,减少QA在开发者已投入其他开发工作时反馈bug从而打断当前的工作进度的现象。
(3) vue单元测试
vue单元测试也是单元测试,它的“单元”泛指vue组件,简单来说就是以vue组件为单位进行的单元测试。
三、HOW
本章节主要从理论层面讲述如何实现vue的单元测试。
(1)测试框架:
vue-cli 自带了测试框架:jest(Javascript单元测试工具)、karma and Mocha、e2e(nightwatch)等。单元测试框架选用karma+mocha+chai。
- Karma:一个测试运行器,用于启动浏览器,运行测试案例并将结果报告给我们。该工具的主要作用是将项目运行在各种主流Web浏览器进行测试。
- Mocha:一个测试框架。可结合chai断言库使用。
- Chai:一个测试断言库,提供了更好的断言语法。所谓断言,就是对组件做一些操作,并预言产生的结果。如果测试结果与断言相同则测试通过。
(2) 运行过程
karma的配置文件中,可以配置files参数,即引入测试脚本,测试运行时会扫描到这些测试脚本,运行其中的测试case,得到测试报告。
四、Use
本章节主要讲述vue单元测试的具体实施,包括测试环境搭建、配置简述、测试脚本编写、测试运行。
(1) 测试环境搭建
创建一个vue项目,init 时 “Set up unit tests”选择yes 、"Pick a test runner"选择Karma即可。vue-cli 会自动生成karma配置文件(karma.conf.js)。
(2) 配置简述
/test/unit/karma.conf.js:
// This is a karma config file. For more details see
// http://karma-runner.github.io/0.13/config/configuration-file.html
// we are also using it with karma-webpack
// https://github.com/webpack/karma-webpack
var webpackConfig = require('../../build/webpack.test.conf') // 引入webpack配置
module.exports = function karmaConfig (config) { // 设置karma配置
config.set({
// to run in additional browsers:
// 1. install corresponding karma launcher
// http://karma-runner.github.io/0.13/config/browsers.html
// 2. add it to the `browsers` array below.
// 设置默认打开的浏览器
browsers: ['PhantomJS'],
// 测试框架
frameworks: ['mocha', 'sinon-chai', 'phantomjs-shim'],
// 设置测试覆盖率输出插件
reporters: ['spec', 'coverage'],
// 测试文件入口
files: ['./index.js'],
// 预处理器--用webpack解析,同时显示测试文件路径
preprocessors: {
'./index.js': ['webpack', 'sourcemap']
},
// 引入webpack
webpack: webpackConfig,
// 是否打印[webpack]打包信息
webpackMiddleware: {
noInfo: true
},
//karma-coverage配置,配置测试覆盖率的输出目录及格式
coverageReporter: {
dir: './coverage',
reporters: [
{ type: 'lcov', subdir: '.' },
{ type: 'text-summary' }
]
}
})
}
test/unit/index.js
import Vue from 'vue'
Vue.config.productionTip = false
// require all test files (files that ends with .spec.js)
// 加载所有的测试脚本
const testsContext = require.context('./spec', true, /\.spec$/)
testsContext.keys().forEach(testsContext)
// require all src files except main.js for coverage.
// you can also change this to match only the subset of files that
// you want coverage for.
// 加载所有的资源文件,及src目录下的除了main.js文件的所有文件,即要覆盖所有的代码
const srcContext = require.context('../../src', true, /^\.\/(?!main(\.js)?$)/)
srcContext.keys().forEach(srcContext)
package.json:
应当包含这样的script:
"unit": "jest --config test/unit/jest.conf.js --coverage",
(3) 测试脚本编写与运行
1、 基础知识:
- 测试脚本都要放在
test/unit/specs/
目录下。 - 脚本命名方式为
[组件名].spec.js
。 - 所谓断言,就是对组件做一些操作,并预言产生的结果。如果测试结果与断言相同则测试通过。
- 单元测试默认测试
src
目录下除了main.js
之外的所有文件,可在test/unit/index.js
文件中修改。 - Chai断言库中,
to be been is that which and has have with at of same
这些语言链是没有意义的,只是便于理解而已。 - 测试脚本由多个
descibe
组成,每个describe
由多个it
组成。
2、describe
的钩子(生命周期)
describe('hooks', function() {
before(function() {
// 在本区块的所有测试用例之前执行
});
after(function() {
// 在本区块的所有测试用例之后执行
});
beforeEach(function() {
// 在本区块的每个测试用例之前执行
});
afterEach(function() {
// 在本区块的每个测试用例之后执行
});
// test cases
});
3、简单的测试脚本:
测试对象:/Src/components/HelloWorld.vue
就是vue创建项目时生成的文件,没有做任何改动,以下是抽取出来的主要代码:
<template>
<div class="hello">
<h1>{{ msg }}</h1>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
}
}
</script>
测试脚本:/test/unit/specs/HelloWorld.spec.js
仍然没有做任何改动,只增加了注释:
import Vue from 'vue'
import HelloWorld from '@/components/HelloWorld'
// 一个 describe 代表一个测试套件,可以有多个 it块
describe('HelloWorld.vue', () => {
// 一个it块代表一个 测试case
it('should render correct contents', () => {
// 获取组件实例
const Constructor = Vue.extend(HelloWorld)
// 将实例挂载到 DOM 上
const vm = new Constructor().$mount()
// 断言实际结果与预期结果一致 ———— 断言“hello”class内的 “h1” 标签文本内容等于‘Welcome to Your Vue.js App’
expect(vm.$el.querySelector('.hello h1').textContent)
.to.equal('Welcome to Your Vue.js App')
})
})
运行单元测试:#npm run unit
查看测试报告(覆盖率):报告自动写入该目录 /test/unit/coverage/lcov-report/ ....
在浏览器查看测试报告:
下次将深入组件测试,编写运行更为复杂的测试脚本。
五、Resource
本章节分享本人在学习过程收集的资料,以供感兴趣者继续深入学习。
(1) 官网:
(2) 社区:
(3) openSource:
(4) 其他: