亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

詳解Vue單元測試Karma+Mocha學習筆記

2019-11-19 14:27:02
字體:
來源:轉載
供稿:網友

在使用vue-cli創建項目的時候,會提示要不要安裝單元測試和e2e測試。既然官方推薦我們使用這兩個測試框架,那么我們就動手去學習實踐一下他們吧。

簡介

Karma

Karma是一個基于Node.js的JavaScript測試執行過程管理工具(Test Runner)。該工具在Vue中的主要作用是將項目運行在各種主流Web瀏覽器進行測試。

換句話說,它是一個測試工具,能讓你的代碼在瀏覽器環境下測試。需要它的原因在于,你的代碼可能是設計在瀏覽器端執行的,在node環境下測試可能有些bug暴露不出來;另外,瀏覽器有兼容問題,karma提供了手段讓你的代碼自動在多個瀏覽器(chrome,firefox,ie等)環境下運行。如果你的代碼只會運行在node端,那么你不需要用karma。

Mocha

Mocha是一個測試框架,在vue-cli中配合chai斷言庫實現單元測試。

而Chai斷言庫可以看Chai.js斷言庫API中文文檔,很簡單,多查多用就能很快掌握。

我對測試框架的理解

npm run unit 執行過程

  1. 執行 npm run unit 命令
  2. 開啟Karma運行環境
  3. 使用Mocha去逐個測試用Chai斷言寫的測試用例
  4. 在終端顯示測試結果
  5. 如果測試成功,karma-coverage 會在 ./test/unit/coverage 文件夾中生成測試覆蓋率結果的網頁。

Karma

對于Karma,我只是了解了一下它的配置選項。

下面是Vue的karma配置,簡單注釋了下:

var webpackConfig = require('../../build/webpack.test.conf')module.exports = function (config) { config.set({  // 瀏覽器  browsers: ['PhantomJS'],  // 測試框架  frameworks: ['mocha', 'sinon-chai', 'phantomjs-shim'],  // 測試報告  reporters: ['spec', 'coverage'],  // 測試入口文件  files: ['./index.js'],  // 預處理器 karma-webpack  preprocessors: {   './index.js': ['webpack', 'sourcemap']  },  // Webpack配置  webpack: webpackConfig,  // Webpack中間件  webpackMiddleware: {   noInfo: true  },  // 測試覆蓋率報告  // https://github.com/karma-runner/karma-coverage/blob/master/docs/configuration.md  coverageReporter: {   dir: './coverage',   reporters: [    { type: 'lcov', subdir: '.' },    { type: 'text-summary' }   ]  } })}

Mocha和chai

我們看下官方的例子(都用注釋來解釋代碼意思了):

import Vue from 'vue' // 導入Vue用于生成Vue實例import Hello from '@/components/Hello' // 導入組件// 測試腳本里面應該包括一個或多個describe塊,稱為測試套件(test suite)describe('Hello.vue', () => { // 每個describe塊應該包括一個或多個it塊,稱為測試用例(test case) it('should render correct contents', () => {  const Constructor = Vue.extend(Hello) // 獲得Hello組件實例  const vm = new Constructor().$mount() // 將組件掛在到DOM上  //斷言:DOM中class為hello的元素中的h1元素的文本內容為Welcome to Your Vue.js App  expect(vm.$el.querySelector('.hello h1').textContent)   .to.equal('Welcome to Your Vue.js App')  })})

需要知道的知識點:

  1. 測試腳本都要放在 test/unit/specs/ 目錄下。
  2. 腳本命名方式為  [組件名].spec.js。
  3. 所謂斷言,就是對組件做一些操作,并預言產生的結果。如果測試結果與斷言相同則測試通過。
  4. 單元測試默認測試 src 目錄下除了 main.js 之外的所有文件,可在 test/unit/index.js 文件中修改。
  5. Chai斷言庫中,to be been is that which and has have with at of same 這些語言鏈是沒有意義的,只是便于理解而已。
  6. 測試腳本由多個  descibe 組成,每個 describe 由多個 it 組成。
  7. 了解異步測試
it('異步請求應該返回一個對象', done => {  request  .get('https://api.github.com')  .end(function(err, res){   expect(res).to.be.an('object');   done();  });});

了解一下 describe 的鉤子(生命周期)

describe('hooks', function() { before(function() {  // 在本區塊的所有測試用例之前執行 }); after(function() {  // 在本區塊的所有測試用例之后執行 }); beforeEach(function() {  // 在本區塊的每個測試用例之前執行 }); afterEach(function() {  // 在本區塊的每個測試用例之后執行 }); // test cases});

實踐

上面簡單介紹了單元測試的用法,下面來動手在Vue中進行單元測試!

util.js

從Vue官方的demo可以看出,對于Vue的單元測試我們需要將組件實例化為一個Vue實例,有時還需要掛載到DOM上。

 const Constructor = Vue.extend(Hello) // 獲得Hello組件實例 const vm = new Constructor().$mount() // 將組件掛載到DOM上

以上寫法只是簡單的獲取組件,有時候我們需要傳遞props屬性、自定義方法等,還有可能我們需要用到第三方UI框架。所以以上寫法非常麻煩。

這里推薦Element的單元測試工具腳本Util.js,它封裝了Vue單元測試中常用的方法。下面demo也是根據該 Util.js來寫的。
這里簡單注釋了下各方法的用途。

/** * 回收 vm,一般在每個測試腳本測試完成后執行回收vm。 * @param {Object} vm */exports.destroyVM = function (vm) {}/** * 創建一個 Vue 的實例對象 * @param {Object|String} Compo   - 組件配置,可直接傳 template * @param {Boolean=false} mounted  - 是否添加到 DOM 上 * @return {Object} vm */exports.createVue = function (Compo, mounted = false) {}/** * 創建一個測試組件實例 * @param {Object} Compo     - 組件對象 * @param {Object} propsData   - props 數據 * @param {Boolean=false} mounted - 是否添加到 DOM 上 * @return {Object} vm */exports.createTest = function (Compo, propsData = {}, mounted = false) {}/** * 觸發一個事件 * 注: 一般在觸發事件后使用 vm.$nextTick 方法確定事件觸發完成。 * mouseenter, mouseleave, mouseover, keyup, change, click 等 * @param {Element} elm   - 元素 * @param {String} name   - 事件名稱 * @param {*} opts      - 配置項 */exports.triggerEvent = function (elm, name, ...opts) {}/** * 觸發 “mouseup” 和 “mousedown” 事件,既觸發點擊事件。 * @param {Element} elm   - 元素 * @param {*} opts     - 配置選項 */exports.triggerClick = function (elm, ...opts) {}

示例一

示例一中我們測試了 Hello 組件的各種元素的數據,學習  util.js 的 destroyVM 和 createTest 方法的用法以及如何獲取目標元素進行測試。獲取DOM元素的方式可查看DOM 對象教程。

Hello.vue

<template> <div class="hello">  <h1 class="hello-title">{{ msg }}</h1>  <h2 class="hello-content">{{ content }}</h2> </div></template><script>export default { name: 'hello', props: {  content: String }, data () {  return {   msg: 'Welcome!'  } }}</script>

Hello.spec.js

import { destroyVM, createTest } from '../util'import Hello from '@/components/Hello'describe('Hello.vue', () => { let vm afterEach(() => {  destroyVM(vm) }) it('測試獲取元素內容', () => {  vm = createTest(Hello, { content: 'Hello World' }, true)  expect(vm.$el.querySelector('.hello h1').textContent).to.equal('Welcome!')  expect(vm.$el.querySelector('.hello h2').textContent).to.have.be.equal('Hello World') }) it('測試獲取Vue對象中數據', () => {  vm = createTest(Hello, { content: 'Hello World' }, true)  expect(vm.msg).to.equal('Welcome!')  // Chai的語言鏈是無意義的,可以隨便寫。如下:  expect(vm.content).which.have.to.be.that.equal('Hello World')  }) it('測試獲取DOM中是否存在某個class', () => {  vm = createTest(Hello, { content: 'Hello World' }, true)  expect(vm.$el.classList.contains('hello')).to.be.true  const title = vm.$el.querySelector('.hello h1')  expect(title.classList.contains('hello-title')).to.be.true  const content = vm.$el.querySelector('.hello-content')  expect(content.classList.contains('hello-content')).to.be.true })})

輸出結果

Hello.vue
  √ 測試獲取元素內容
  √ 測試獲取Vue對象中數據
  √ 測試獲取DOM中是否存在某個class

示例二

示例二中我們使用 createTest 創建測試組件測試點擊事件,用 createVue 創建Vue示例對象測試組件 Click 的使用。這里主要可以看下到 createVue 方法的使用。

Click.vue

<template> <div>  <span class="init-num">初始值為{{ InitNum }}</span><br>  <span class="click-num">點擊了{{ ClickNum }}次</span><br>  <span class="result-num">最終結果為{{ ResultNum }}</span><br>  <button @click="add">累加{{ AddNum }}</button> </div></template><script>export default { name: 'Click', props: {  AddNum: {   type: Number,   default: 1  },  InitNum: {   type: Number,   default: 1  } }, data () {  return {   ClickNum: 0,   ResultNum: 0  } }, mounted () {  this.ResultNum = this.InitNum }, methods: {  add () {   this.ResultNum += this.AddNum   this.ClickNum++   this.$emit('result', {    ClickNum: this.ClickNum,    ResultNum: this.ResultNum   })  } }}</script>

Click.spec.js

import { destroyVM, createTest, createVue } from '../util'import Click from '@/components/Click'describe('click.vue', () => { let vm afterEach(() => {  destroyVM(vm) }) it('測試按鈕點擊事件', () => {  vm = createTest(Click, {   AddNum: 10,   InitNum: 11  }, true)  let buttonElm = vm.$el.querySelector('button')  buttonElm.click()  buttonElm.click()  buttonElm.click()  // setTimeout 的原因  // 在數據改變之后,界面的變化會有一定延時。不用timeout有時候會發現界面沒有變化  setTimeout(done => {   expect(vm.ResultNum).to.equal(41)   expect(vm.$el.querySelector('.init-num').textContent).to.equal('初始值為11')   expect(vm.$el.querySelector('.click-num').textContent).to.equal('點擊了3次')   expect(vm.$el.querySelector('.result-num').textContent).to.equal('最終結果為41')   done()  }, 100) }) it('測試創建Vue對象', () => {  let result  vm = createVue({   template: `    <click @click="handleClick"></click>   `,   props: {    AddNum: 10,    InitNum: 11   },   methods: {    handleClick (obj) {     result = obj    }   },   components: {    Click   }  }, true)  vm.$el.click()  vm.$nextTick(done => {   expect(result).to.be.exist   expect(result.ClickNum).to.equal(1)   expect(result.ResultNum).to.be.equal(21)   done()  })})

輸出結果

click.vue
  √ 測試按鈕點擊事件
  √ 測試創建Vue對象

其他

所有示例代碼都放Github倉庫中便于查看。如果想查看更多好的測試用例,建議配合 Util.js 看一下 Element 的單元測試腳本的寫法,里面有很多測試腳本可以供我們學習。作為被廣大Vue用戶使用的UI組件庫,測試腳本肯定也寫很很不錯的~甚至可以將這些腳本照抄一遍,相信這會對學習Vue組件的單元測試有很大幫助。

下面是本人看Element單元測試的筆記,供參考。

Util.js 方法包含了大多數Vue組件化的測試需求。

vm.$el vm.$nextTick 和 vm.$ref 都是在測試過程中比較常用的一些Vue語法糖。

需要注意: vm.$nextTick 方法是異步的,所以需要在里面使用done方法。

異步斷言,方法參數需要是 _ 或者 done

大多數時候查詢元素通過 querySelector 方法查詢class獲得

vm.$el.querySelector('.el-breadcrumb').innerText

大多數情況下查詢是否存在某個Class通過 classList.contains 方法獲得,查找的結果為 true 或 false

vm.$el .classList.contains('el-button--primary')

異步測試必須以 done() 方法結尾。setTimeout 和 vm.$nextTick 是常用的異步測試。

實現按鈕點擊:通過獲取按鈕元素 btn,執行 btn.click() 方法實現。

由于 Vue 進行異步更新DOM 的情況,一些依賴DOM更新結果的斷言必須在 Vue.nextTick 回調中進行。

triggerEvent(vm.$refs.cascader.$el, 'mouseenter');vm.$nextTick(_ => {   vm.$refs.cascader.$el.querySelector('.el-cascader__clearIcon').click();   vm.$nextTick(_ => {    expect(vm.selectedOptions.length).to.be.equal(0);    done();   });});

Vue.js學習系列項目地址:https://github.com/violetjack/VueStudyDemos

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久精品这里热有精品| 中文字幕在线观看日韩| 欧美日韩999| 热久久美女精品天天吊色| 国产国产精品人在线视| www.亚洲一区| 亚洲精品国产品国语在线| 亚洲午夜av电影| 日韩亚洲成人av在线| 性色av一区二区三区红粉影视| 亚洲精品乱码久久久久久按摩观| 欧美性xxxxxxx| 日韩美女av在线| 成人免费观看网址| 亚洲国产精品推荐| 久久久免费在线观看| 国产福利精品在线| 久久影视电视剧免费网站| 亚洲黄色片网站| 日韩中文字幕在线观看| 中文字幕自拍vr一区二区三区| 国产成人精品优优av| 欧美噜噜久久久xxx| 久久在线免费视频| 精品亚洲永久免费精品| 亚洲人午夜精品免费| 欧美一级视频一区二区| 一区二区三区四区精品| 亚洲国产高潮在线观看| 亚洲成人激情图| 91免费视频国产| 97欧美精品一区二区三区| 国产91精品久久久久| 久久精品中文字幕一区| 亚洲成人久久久久| 欧美亚洲日本网站| 亚洲国产欧美一区二区丝袜黑人| 精品亚洲一区二区三区在线观看| 久久天天躁夜夜躁狠狠躁2022| 亚洲欧美国产精品| 日韩激情视频在线播放| 日韩精品在线免费播放| 欧美性做爰毛片| 久久99久久久久久久噜噜| 欧美三级xxx| 亚洲国产精品99久久| 精品国产精品三级精品av网址| 麻豆一区二区在线观看| 精品国产乱码久久久久久虫虫漫画| 亚洲精品www久久久| 国产成人精品电影久久久| 91色在线观看| 国产精品私拍pans大尺度在线| 7m第一福利500精品视频| 亚洲国产成人在线播放| 欧美丰满少妇xxxxx做受| 欧美午夜片在线免费观看| 色偷偷av一区二区三区| 成人一区二区电影| 国产欧美精品一区二区三区介绍| 日韩精品免费看| 第一福利永久视频精品| 亚洲午夜av久久乱码| 久久久精品久久久| 91黑丝在线观看| 久久久久99精品久久久久| xxxx性欧美| 中文综合在线观看| 热re91久久精品国99热蜜臀| 深夜福利国产精品| 亚洲欧美另类人妖| 精品成人国产在线观看男人呻吟| 高清欧美性猛交| 亚洲成人久久一区| 91精品国产高清久久久久久91| 欧美性感美女h网站在线观看免费| 欧美与黑人午夜性猛交久久久| 日韩小视频网址| 欧美精品18videos性欧美| 色视频www在线播放国产成人| 日韩精品免费在线视频观看| 久久精品国亚洲| 日韩视频在线免费| 久久男人的天堂| 久热精品视频在线观看| 午夜精品久久久久久久男人的天堂| 黑人巨大精品欧美一区二区三区| 欧美日本黄视频| 亚洲高清久久网| 欧美精品www在线观看| 亚洲自拍中文字幕| 欧美成人精品三级在线观看| 日韩在线观看免费高清完整版| 久久电影一区二区| 欧美另类暴力丝袜| 亚洲国产毛片完整版| 久久综合色88| 国产精品美女在线| 狠狠色狠狠色综合日日五| 亚洲开心激情网| 日韩大胆人体377p| 日韩专区在线观看| 久久91亚洲精品中文字幕| 国产精品欧美日韩久久| 成人免费黄色网| 亚洲国产精品一区二区久| 日本在线精品视频| 国产欧亚日韩视频| 欧美在线观看网址综合| 成人h视频在线观看播放| 亚洲成人a**站| 久久久精品一区二区| 成人福利在线观看| 国产亚洲精品一区二555| 97色在线视频| 久久久久久久久电影| 精品国产户外野外| 在线电影av不卡网址| 日韩欧美极品在线观看| 欧美中文字幕在线| 久久久久久成人| 日韩av中文字幕在线| 国产精品永久在线| 精品久久久久久久久中文字幕| 日韩精品中文在线观看| 亚洲aⅴ男人的天堂在线观看| 一区二区三区在线播放欧美| 精品视频久久久| 在线电影中文日韩| 欧美黑人xxxⅹ高潮交| 亚洲黄色片网站| 色多多国产成人永久免费网站| 浅井舞香一区二区| 免费99精品国产自在在线| 亚洲精品理论电影| 亚洲人成在线一二| 在线观看欧美视频| 国产精品久久久久久久久久久久久| 亚洲欧洲在线视频| 热re91久久精品国99热蜜臀| 国产精品一久久香蕉国产线看观看| 粗暴蹂躏中文一区二区三区| 久久影院在线观看| 黄色精品在线看| 在线激情影院一区| 国产精品久久久久久久app| 久久久久久久久久亚洲| 国产精品99久久久久久www| 亚洲一级片在线看| 青青草国产精品一区二区| 中文字幕一精品亚洲无线一区| 国产精品久久久亚洲| 97在线精品视频| 高清一区二区三区四区五区| 欧美日本国产在线| 色综合导航网站| 亚洲精品在线看| 国产精品人成电影在线观看| 亚洲美女av在线播放| 九九热精品视频在线播放| 欧美精品一区二区三区国产精品| 午夜精品三级视频福利| 欧美国产日韩一区二区在线观看| 日韩在线视频免费观看高清中文|