前端單元測試怎麼寫(以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,配置文件裏需要修改,否則無法啓動命令,其他操作相同。
在這裏插入圖片描述

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