前端单元测试怎么写(以Vue为例)

单元测试是什么

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

单元测试的意义

1、分模块开发,方便定位到哪个模块出现问题
2、保证了代码质量
3、驱动开发(先写单元测试,通过再写代码)

单元测试两种类型

TDD(测试驱动开发,从需求角度出发)
我需要的结果是什么?如果不是即为错误
针对于数据,面向的是最终的值,适用于开发人员
开发流程:需求分析->编写单元测试->编写代码使单元测试通过->重构

BDD(行为驱动开发,从具体功能角度出发)
结果应该是什么?如果不是即为错误
面向的是最终的产出效果,适用于需求客户人员
开发流程:从业务角度定义目标->找到实现目标的方法->编写单元测试->实现行为->检查产品

单元测试核心内容

测试框架
帮助测试得以运行
Jest-基于Jasmine,对react友好
Jasmine-BDD风格,自带assert和mock(大集成)
Mocha-全面适合node和浏览器两端
Qunit-出自jquery,后来独立出来

断言库(assert)
帮助检查结果
chai-支持所有风格,全面
Assert-node环境直接使用

Mock库
帮助屏蔽方法、数据及相关依赖,避免外部数据对测试产生影响
sinon

test runner
提供运行环境,使得方法能够运行
karma

覆盖率工具
测试比例,明确测试了多少内容
istanbul

单元测试组成部分

在这里插入图片描述

测试人员与前端单元测试工作区别

测试用例(测试人员编写)
为了某个特殊目标而编织的一系列测试输入,执行以及输出结果,来测试是否满足需求
单元测试(前端编写)

以Vue为实例编写单元测试

1、脚手架安装项目,选择单元测试
在这里插入图片描述
2、生成目录如下
在这里插入图片描述
karma.conf.js配置文件说明

var webpackConfig = require('../../build/webpack.test.conf')

module.exports = function karmaConfig (config) {
  config.set({
    //模拟环境
    browsers: ['PhantomJS'],//无头浏览器,不属于任何厂家,单纯的一个javascript执行环境
    //所用到的各种库,mocha框架,sinon-chai断言库
    frameworks: ['mocha', 'sinon-chai', 'phantomjs-shim'],
    //覆盖率暴露到哪里
    reporters: ['spec', 'coverage'],
    //需要加载到浏览器的文件
    files: ['./index.js'],
    //使用前的处理
    preprocessors: {
      './index.js': ['webpack', 'sourcemap']
    },
    webpack: webpackConfig,
    webpackMiddleware: {
      noInfo: true
    },
    //指定报告输出的类型和目录
    coverageReporter: {
      dir: './coverage',
      reporters: [
        { type: 'lcov', subdir: '.' },
        { type: 'text-summary' }
      ]
    }
  })
}

index.js文件说明

import Vue from 'vue'
Vue.config.productionTip = false
//require.context将指定路径下所有符合规则的文件都引入
const testsContext = require.context('./specs', true, /\.spec$/)
testsContext.keys().forEach(testsContext)
//业务代码引入
const srcContext = require.context('../../src', true, /^\.\/(?!main(\.js)?$)/)
srcContext.keys().forEach(srcContext)

3、编写单元测试
.spec.js文件下编写单元测试

import Vue from 'vue'
import HelloWorld from '@/components/HelloWorld'
import axios from 'axios'
import { expect } from 'chai'
//整个组件测试描述
describe('HelloWorld.vue', () => {
  //拿到当前组件的构造函数
  const Constructor = Vue.extend(HelloWorld)
  //挂载,模拟渲染过程
  const vm = new Constructor().$mount()
  //每一个it就是对于一个方法的单元测试
  //描述测试
  it('should render correct contents', () => {
    expect(vm.$el.querySelector('.hello h1').textContent)
      .to.equal('Welcome to Your Vue.js App')
  })
  //检测一个方法
  it('m1 should add two arguments', () => {
    const m1 = vm.m1
    expect(m1(2, 3)).to.equal(5)
  })
  //检测数据更新
  it('should change correct content', () => {
    vm.m2();
    //需要等到页面加载完毕,再去进行数据更改
    Vue.nextTick(()=>{
      expect(vm.$el.querySelector('.hello h1').textContent)
      .to.equal('123')
    })
  })
  //检测异步方法
  it('async m3 should return 6', () => {
    vm.m3(2, 4, (num) => {
      expect(num).to.equal(6)
    })
  })
  //检测接口请求
  it('api request', () => {
    //屏蔽真正的请求
    let axiosstub = sinon.stub(axios,'get')
    //提供模拟真正请求的数据
    let callback = sinon.spy(() => {
      return 5
    })
    const getmes = vm.getmes
    const finalData = getmes(callback)
    expect(finalData).to.equal(4)
  })
})

组件内编写方法

<script>
import axios from 'axios'
export default {
  name: 'HelloWorld',
  data () {
    return {
      msg: 'Welcome to Your Vue.js App'
    }
  },
  methods:{
    m1(a,b){
      return a+b
    },
    m2(){
      this.msg = 123
    },
    m3(a, b, cb){//入侵一个cb
      setTimeout(()=>{
        cb(a + b)
      }, 2000)
    },
    getmes(cb){
      axios.get('/aaa/bbb')
      let res = cb()
      res-=1
      return res
    }
  }
}
</script>

4、npm run unit进行检测
在这里插入图片描述

注意

如果选择了jest,配置文件里需要修改,否则无法启动命令,其他操作相同。
在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章