什么是单元测试
-
目标
- 对软件中最小可测试单元 (一个方法) 进行测试
-
意义
- 分模块开发,方便定位到哪个单元出问题
- 保证代码质量
- 驱动开发: 立项 -> 测试用例 -> 编写单元测试 -> 编码使单元测试通过 -> 发布
-
单元测试类型
- TDD(专业技能):
- 测试驱动开发,从需求角度看。需要的结果是什么,不是就出错。
- 需求分析 -> 编写单元测试 -> 编码使单元测试通过 -> 重构
- eg: m1(2, 4) => 输出 8
- BDD(可以不具备专业技能):
- 行为驱动开发,从具体功能角度出发看。结果应该是什么,不是就出错。
- 业务角度出发定义目标 -> 找到实现目标的方法 -> 编写单元测试 -> 实现行为 -> 检查产品
- eg: m1(2, 4) => 页面效果
- TDD(专业技能):
-
组成部分
- 被测试的方法 -> 准备数据、依赖(Mock库) -> 执行方法(框架、testRunner) -> 检查结果 (断言库)
-
测试用例
- 输入数据 -> 一定条件下执行 -> 预期结果
单元测试的核心内容
- 测试框架
- Jest: 基于jasmine, 对react友好
- Jasmine: bdd风格,自带assert和mock
- Macha: 全面适合node和浏览器两个端
- Qunit: 出自JQuery,后来独立出来
- 断言库: 检查结果
- Chai: 支持所有风格,全面,建议使用
- Should
- expect
- Assert: node环境使用
- Mock库: 屏蔽方法依赖数据或函数,使得测试专一函数得以实现
- sinon: 前端占比较大,非必须
- Test Runner: 运行环境,无界面浏览器环境
- karma
- 覆盖率工具: 对结果进行分析
- istanbul
Vue实践
- jest/ mocha + karma /none: 以下代码选mocha + karma为例子
- karma.config.js
config.set({
browser: ['PhantomJs'], // 无头浏览器,单纯的js执行环境
// 框架:测试框架,断言库,浏览器
frameworks: ['mocha', 'sinon-chai', 'phantomjs-shim'],
reporters: ['spec', 'coverage'], // 测试文件目录,输出文件目录
})
- HelloWord.js
data: () => {},
methods: {
m1 (a, b) {
return a + b
},
m2 () {
this.msg = 123
},
m3 (a, b, cb) { // cb为入侵函数
setTimeout(() => {
cb(a + b)
}, 2000)
},
getMsg (cb) { // cb为入侵函数
axio.get('http...') // 屏蔽真正请求
var res = cb() // 提供模拟数据
res--
return res
}
}
- spec.js
import HelloWorld from '@/components/HelloWorld'
import axios from 'axios'
describe('HelloWorld.vue', () => { // 一个组件
// Vue.extend获取组件构造函数
const Constructor = Vue.extend(HelloWorld)
// 生成实例,$mount挂载实例
const vm = new Constructor().$mount()
// 测试渲染
it('should reder correct contents', () => {
// $el获取dom
expect(vm.$el.querySelector('.hello h1').textContent)
.to.equal('Welcome to your Vue.js App')
})
// 测试静态方法
it('m1 should add two arugments', () => {
const m1 = vm.m1
expect(m1(2, 3)).to.equal(5)
})
// 测试数据更新
it('should change correct contents', () => {
vm.m2() // 该参数更改模板数据
Vue.nextTick(() => {
expect(vm.$el.querySelector('.hello msg').textContent).to.equal('123')
})
})
// 测试异步方法
it('async m3 should return correct', () => {
vm.m3(2, 4, (sum) => {
expect(num).to.equal(6)
})
})
it('http request', () => {
// 屏蔽axios.get
let axiosstub = sinon.stub(axios, 'get')
// 模拟间谍函数
let callback = sinon.spy(() => {
return 5
})
const getMsg = vm.getMsg
const finalData = getMsg(callback)
expect(finalData).to.equal(4)
})
})
- Jest
- 使用vue-cli2生成,要运行单元测试需要修改jest.conf.js
module.exports = {
+ verbose: true,
+ testURL: 'http://localhost/',
- mapCoverage: true
}