本篇文章主要介紹了詳解Vue單元測試Karma Mocha學習筆記,現在分享給大家,也給大家做個參考。
在使用vue-cli建立專案的時候,會提示要不要安裝單元測試和e2e測試。既然官方推薦我們使用這兩個測試框架,那麼我們就動手去學習實踐一下他們吧。
簡介
Karma
#Karma是基於Node.js的JavaScript測試執行程式管理工具(Test Runner) 。該工具在Vue中的主要作用是將專案運行在各種主流網頁瀏覽器進行測試。
換句話說,它是一個測試工具,能讓你的程式碼在瀏覽器環境下測試。需要它的原因在於,你的程式碼可能是設計在瀏覽器端執行的,在node環境下測試可能有些bug暴露不出來;另外,瀏覽器有相容問題,karma提供了手段讓你的程式碼自動在多個瀏覽器(chrome,firefox,ie等)環境下運作。如果你的程式碼只會運行在node端,那麼你不需要用karma。
Mocha
Mocha是一個測試框架,在vue-cli中配合chai斷言函式庫實作單元測試。
而Chai斷言庫可以看Chai.js斷言庫API中文文檔,很簡單,多查多用就能很快掌握。
我對測試框架的理解
npm run unit 執行過程
執行npm run unit 指令
開啟Karma運行環境
#使用Mocha去逐一測試用Chai斷言寫的測試案例
#在終端機顯示測試結果
如果測試成功,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') }) })
需要知道的知識點:
測試腳本都要放在test/unit/specs/ 目錄下。
腳本命名方式為 [元件名稱].spec.js。
所謂斷言,就是對元件做一些操作,並預言產生的結果。如果測試結果與斷言相同則測試通過。
單元測試預設測試 src 目錄下除了 main.js 之外的所有文件,可在 test/unit/index.js 檔案中修改。
Chai斷言庫中,to be been is that which and has have with at of same 這些語言鍊是沒有意義的,只是便於理解而已。
測試腳本由多個 descibe 組成,每個 describe 由多個 it 組成。
了解非同步測試
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> <p class="hello"> <h1 class="hello-title">{{ msg }}</h1> <h2 class="hello-content">{{ content }}</h2> </p> </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> <p> <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> </p> </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>
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() }) })
√ 測試按鈕點選事件
√ 測試建立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單元測試中Karma+Mocha的詳細內容。更多資訊請關注PHP中文網其他相關文章!