日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > vue >内容正文

vue

vue 打开一个iframe_Vue 之五 —— 单元测试

發(fā)布時間:2023/12/2 vue 54 豆豆
生活随笔 收集整理的這篇文章主要介紹了 vue 打开一个iframe_Vue 之五 —— 单元测试 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

單元測試(unit testing):是指對軟件中的最小可測試單元進(jìn)行檢查和驗(yàn)證。代碼的終極目標(biāo)有兩個,第一個是實(shí)現(xiàn)需求,第二個是提高代碼質(zhì)量和可維護(hù)性。單元測試是為了提高代碼質(zhì)量和可維護(hù)性,是實(shí)現(xiàn)代碼的第二個目標(biāo)的一種方法。對vue組件的測試是希望組件行為符合我們的預(yù)期。

本文將從框架選型,環(huán)境搭建,使用方式,vue組件測試編寫原則四個方面講述如何在vue項(xiàng)目中落地單元測試。


一、框架選型

cypress / vue-test-utils

選擇vue-test-utils 是因?yàn)樗枪俜酵扑]的vue component 單元測試庫。

選擇cypress而不是jest 主要是因?yàn)?#xff1a;

  • 測試環(huán)境的一致性: 在cypress上面跑的測試代碼是在瀏覽器環(huán)境上的,而非像jest等在node上的。另外由于cypress在瀏覽器環(huán)境上運(yùn)行,測試dom相關(guān)無需各種mock(如node-canvas等)
  • 統(tǒng)一測試代碼風(fēng)格、避免技術(shù)負(fù)擔(dān): 本身定位 e2e, 但是支持 unit test。
  • 支持CI環(huán)境

此外cypress還有很多非常棒的Features,感興趣的朋友自行參考cypress官方文檔。


二、環(huán)境搭建

1、安裝依賴

npm i cypress @cypress/webpack-preprocessor start-server-and-test nyc babel-plugin-istanbul @vue/test-utils -D

note: 如果是使用vue cli3創(chuàng)建的項(xiàng)目,可以使用

# vue add @vue/cli-plugin-e2e-cypress # npm i @cypress/webpack-preprocessor start-server-and-test nyc babel-plugin-istanbul @vue/test-utils -D

@cypress/webpack-preprocessor:引入webpack 預(yù)處理器

start-server-and-test:啟動dev-server 監(jiān)聽端口啟動成功,再執(zhí)行測試命令。cypress 需要dev-server啟動才能測試。

nyc babel-plugin-istanbul:覆蓋率統(tǒng)計相關(guān)

2、添加/修改cypress.json文件

{"baseUrl": "http://localhost:9001","coverageFolder": "coverage","integrationFolder": "src","testFiles": "**/*.spec.js","video": false,"viewportHeight": 900,"viewportWidth": 1600,"chromeWebSecurity": false }

3、修改package.json配置

"scripts": {"cy:run": "cypress run","cy:open": "cypress open","cy:dev": "start-server-and-test start :9001 cy:open","coverage": "nyc report -t=coverage","test": "rm -rf coverage && start-server-and-test start :9001 cy:run && nyc report -t=coverage"},

4、修改cypress/plugins/index.js(使用vue add @vue/cli-plugin-e2e-cypress的是tests/e2e//plugins/index.js)

// vue cli3 版本 const webpack = require('@cypress/webpack-preprocessor'); const webpackOptions = require('@vue/cli-service/webpack.config');webpackOptions.module.rules.forEach(rule => {if (!Array.isArray(rule.use)) return null;rule.use.forEach(opt => {if (opt.loader === 'babel-loader') {opt.options = {plugins: ['istanbul']};}}); });const options = {webpackOptions,watchOptions: {}, };module.exports = (on, config) => {on('file:preprocessor', webpack(options));return Object.assign({}, config, {integrationFolder: 'src',// screenshotsFolder: 'cypress/screenshots',// videosFolder: 'cypress/videos',// supportFile: 'cypress/support/index.js'}) }; // webpack4 版本const webpack = require('@cypress/webpack-preprocessor'); const config = require('../../webpack.base'); config.mode = 'development'; config.module.rules[0].use.options = {plugins: ['istanbul'] };module.exports = (on) => {const options = {// send in the options from your webpack.config.js, so it works the same// as your app's codewebpackOptions: config,watchOptions: {},};on('file:preprocessor', webpack(options)); };

5、修改cypress/support

// support/index.jsimport './commands'; import './istanbul';

在support目錄里添加istanbul.js文件

// https://github.com/cypress-io/cypress/issues/346#issuecomment-365220178 // https://github.com/cypress-io/cypress/issues/346#issuecomment-368832585 /* eslint-disable */ const istanbul = require('istanbul-lib-coverage');const map = istanbul.createCoverageMap({}); const coverageFolder = Cypress.config('coverageFolder'); const coverageFile = `${ coverageFolder }/out-${Date.now()}.json`;Cypress.on('window:before:unload', e => {const coverage = e.currentTarget.__coverage__;if (coverage) {map.merge(coverage);} });after(() => {cy.window().then(win => {const specWin = win.parent.document.querySelector('iframe[id~="Spec:"]').contentWindow;const unitCoverage = specWin.__coverage__;const coverage = win.__coverage__;if (unitCoverage) {map.merge(unitCoverage);}if (coverage) {map.merge(coverage);}cy.writeFile(coverageFile, JSON.stringify(map));cy.exec('npx nyc report --reporter=html -t=coverage')cy.exec('npm run coverage').then(coverage => {// output coverage reportconst out = coverage.stdout// 替換bash紅色標(biāo)識符.replace(/[31;1m/g, '').replace(/[0m/g, '')// 替換粗體標(biāo)識符.replace(/[3[23];1m/g, '');console.log(out);}).then(() => {// output html file link to current test reportconst link = Cypress.spec.absolute.replace(Cypress.spec.relative, `${coverageFolder}/${Cypress.spec.relative}`).replace('cypress.spec.', '');console.log(`check coverage detail: file://${link}.html`);});}); });

6、修改package.json (推薦使用git push hooks 里跑test)

"gitHooks": {"pre-push": "npm run test"},"nyc": {"exclude": ["**/*.spec.js","cypress","example"]}

note: 如果項(xiàng)目使用了sass來寫css,則必須指定node版本為v8.x.x,這個算是cypress的bug。Issuess

# npm install n -g # sudo n v8.9.0 # npm rebuild node-sass

這樣在git push之前會先跑單元測試,通過了才可以push成功。


三、使用方法

  • 對于各個 utils 內(nèi)的方法以及 vue組件,只需在其目錄下補(bǔ)充同名的 xxx.spec.js,即可為其添加單元測試用例。
  • 斷言語法采用 cypress 斷言: https://docs.cypress.io/guides/references/assertions.html#Chai
  • vue組件測試使用官方推薦的test-utils: https://vue-test-utils.vuejs.org/
  • npm 命令測試:
  • npm run cy:run (終端測試,前置條件:必須啟動本地服務(wù))
  • npm run cy:open (GUI 測試,前置條件:必須啟動本地服務(wù))
  • npm run cy:dev (GUI測試, 自動啟動本地服務(wù),成功后打開GUI)
  • npm run test (終端測試, 自動啟動本地服務(wù),并且統(tǒng)計覆蓋率,在終端運(yùn)行,也是CI運(yùn)行的測試命令)

四、測試原則

1、明白要測試的是什么

不推薦一味追求行級覆蓋率,因?yàn)樗鼤?dǎo)致我們過分關(guān)注組件的內(nèi)部實(shí)現(xiàn)細(xì)節(jié),而只關(guān)注其輸入和輸出。一個簡單的測試用例將會斷言一些輸入 (用戶的交互或 prop 的改變) 提供給某組件之后是否導(dǎo)致預(yù)期結(jié)果 (渲染結(jié)果或觸發(fā)自定義事件)。

2、測試公共接口

a、如果模板有邏輯,我們應(yīng)該測試它

// template <button ref="logOutButton" v-if="loggedIn">Log out</button> // Button.spec.jsconst PropsData = {loggedIn: true, };it('hides the logOut button if user is not logged in', () => {const wrapper = mount(UserSettingsBar, { PropsData });const { vm } = wrapper;expect(vm.$refs.logOutButton).to.exist();wrapper.setProps({ loggedIn: false });expect(vm.$refs.logOutButton).not.to.exist(); });

原則:Props in Rendered Output

b、什么超出了我們組件的范圍

  • 實(shí)現(xiàn)細(xì)節(jié),過分關(guān)注組件的內(nèi)部實(shí)現(xiàn)細(xì)節(jié),從而導(dǎo)致瑣碎的測試。
  • 測試框架本身, 這是vue應(yīng)該去做的事情。
1、<p> {{ myProp }} </p> expect(p.text()).to.be(/ prop value /);2、prop 校驗(yàn)

c、權(quán)衡

Integration Test

// Count.spec.jsit('should display the updated count after button is clicked', () => {const wrapper = mount(Count, { count: 0});const ButtonInstance = wrapper.find(Button);const buttonEl = ButtonInstance.find('button')[0]; // find button clickbuttonE1.trigger('click');const CounterDisplayInstance = wrapper.find(CounterDisplay);const displayE1 = CounterDisplayInstance.find('.count-display')[0];expect(displayE1.text()).to.equal('1'); // find display, assert render });

Shallow Test

// Count.spec.jsit('should pass the "count" prop to CounterDisplay', () => {const counterWrapper = shallow(Counter, {count: 10});const counterDisplayWrapper = counterWrapper.find(CounterDisplay);// we dont't care how this will be renderedexpect(counterDisplayWrapper.propsData().count).to.equal(10); });it('should update the "count" prop by 1 on Button "increment" event', () => {const counterWrapper = shallow(Counter, {count: 10});const buttonWrapper = counterWrapper.find(Button);// we don't care how this was triggeredbuttonWrapper.vm.$emit('increment');expect(CounterDisplay.propsData().count).to.equal(11); });


參考:

cypress-vue-unit-test

Vue Test Utils

Component Tests with Vue.js

總結(jié)

以上是生活随笔為你收集整理的vue 打开一个iframe_Vue 之五 —— 单元测试的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。