网易云-vue单元测试

222 阅读2分钟

什么是单元测试

  • 目标

    • 对软件中最小可测试单元 (一个方法) 进行测试
  • 意义

    • 分模块开发,方便定位到哪个单元出问题
    • 保证代码质量
    • 驱动开发: 立项 -> 测试用例 -> 编写单元测试 -> 编码使单元测试通过 -> 发布
  • 单元测试类型

    • TDD(专业技能):
      • 测试驱动开发,从需求角度看。需要的结果是什么,不是就出错。
      • 需求分析 -> 编写单元测试 -> 编码使单元测试通过 -> 重构
      • eg: m1(2, 4) => 输出 8
    • BDD(可以不具备专业技能):
      • 行为驱动开发,从具体功能角度出发看。结果应该是什么,不是就出错。
      • 业务角度出发定义目标 -> 找到实现目标的方法 -> 编写单元测试 -> 实现行为 -> 检查产品
      • eg: m1(2, 4) => 页面效果
  • 组成部分

    • 被测试的方法 -> 准备数据、依赖(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
    }