前端單元測(cè)試配置-Mocha和Jest結(jié)合Vue&React&Angular

結(jié)合現(xiàn)有項(xiàng)目,將使用到的前端框架(Vue橄务、Angular幔托、React)進(jìn)行單元測(cè)試配置,整理配置文檔

Vue

vue-cli在創(chuàng)建項(xiàng)目時(shí)可選擇單元測(cè)試框架(Mocha 或 Jest)仪糖,此處包含兩種測(cè)試框架配置

Vue & Mocha

項(xiàng)目創(chuàng)建

項(xiàng)目創(chuàng)建時(shí)選擇 Mocha 的Unit Testing

vue create vue-mocha

# 選擇手動(dòng)配置
? Please pick a preset: 
  zcloud (router, vuex, less, babel, eslint, unit-jest) 
  default (babel, eslint) 
? Manually select features 

? Please pick a preset: Manually select features
? Check the features needed for your project: 
 ? Babel
 ? TypeScript
 ? Progressive Web App (PWA) Support
 ? Router
 ? Vuex
 ? CSS Pre-processors
 ? Linter / Formatter
 ? Unit Testing
?? E2E Testing

# 單元測(cè)試 mocha + chai
 ? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, Router, Vuex, CSS Pre-processors, Linter, Unit, E2E
? Use history mode for router? (Requires proper server setup for index fallback in production) Yes
? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): Sass/SCSS (with node-sass)
? Pick a linter / formatter config: Standard
? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection)Lint on save
? Pick a unit testing solution: (Use arrow keys)
? Mocha + Chai 
  Jest 

添加測(cè)試報(bào)告mochawesome

現(xiàn)有架構(gòu)測(cè)試報(bào)告都是在命令行展示柑司,現(xiàn)在我們要將結(jié)果輸出并展示在頁(yè)面上

首先在項(xiàng)目中安裝 mochawesome:

npm install --save-dev mochawesome

然后在 package.json 中修改 test:unit 命令如下:

"test:unit": "vue-cli-service test:unit --reporter=mochawesome"

添加測(cè)試覆蓋率nyc

首先,在項(xiàng)目中安裝所需依賴(lài):

npm i --save-dev babel-plugin-istanbul istanbul-instrumenter-loader nyc

接著在項(xiàng)目根目錄下新建 nyc.config.js 文件锅劝,其內(nèi)容如下:

// 探索istanbul/nyc代碼覆蓋工具的原理 https://zhuanlan.zhihu.com/p/88524418
module.exports = {
  'check-coverage': true,
  'per-file': true,
  'lines': 0,
  'statements': 0,
  'functions': 0,
  'branches': 0,
  'include': [
    'src/**/*.js',
    'src/**/*.vue'
  ],
  'exclude': [
    'src/abandon-ui/**',
    'src/*.js',
    '**/*.spec.js'
  ],
  'reporter': [
    'lcov',
    'text',
    'text-summary'
  ],
  'extension': [
    '.js',
    '.vue'
  ],
  'cache': true,
  'all': true
}

完成后攒驰,在項(xiàng)目根目錄新建 vue.config.js, 其內(nèi)容如下:

const path = require('path')
const testMode = process.env.NODE_ENV === 'test'

module.exports = {
  lintOnSave: false,
  productionSourceMap: false,

  chainWebpack: config => {

    if (testMode) {
      config.merge({
        devtool: 'eval'
      })
      config.module
        .rule('istanbul')
        .test(/\.(js|vue)$/)
        .include
        .add(path.resolve(__dirname, '/src'))
        .end()
        .use('istanbul-instrumenter-loader')
        .loader('istanbul-instrumenter-loader')
        .options({ esModules: true })
        .before('babel-loader')
    }
  }
}

完成后,打開(kāi)項(xiàng)目根目錄下的 babel.config.js 文件故爵,修改如下:

const testMode = process.env.NODE_ENV === 'test'

module.exports = {
  presets: ['@vue/cli-plugin-babel/preset']
  presets: ['@vue/cli-plugin-babel/preset'],
  plugins: testMode ? ['babel-plugin-istanbul'] : []
}

最后玻粪,打開(kāi) package.json 文件,修改 test:unit 命令:

"test:unit": "nyc vue-cli-service test:unit --reporter=mochawesome"

單元測(cè)試文件書(shū)寫(xiě)位置調(diào)整

如果我們的項(xiàng)目是一個(gè)去中心化的架構(gòu)诬垂,我們可能希望我們的單元測(cè)試文件位于我們的組件旁邊劲室,而不是都寫(xiě)在 tests/unit/ 目錄下。

在 tests/unit 目錄下新建 index.spec.js 文件结窘,其內(nèi)容如下:

// require all src files that ends with .spec.js
const srcContext = require.context('../../src/', true, /\.spec.js$/)
srcContext.keys().forEach(srcContext)

修改.eslintrc.js 配置

overrides: [
  {
    files: [
      '**/__tests__/*.{j,t}s?(x)',
      '**/tests/unit/**/*.spec.{j,t}s?(x)',
      '**/src/**/*.spec.{j,t}s?(x)'
    ],
    env: {
      mocha: true
    }
  }
]

至此很洋,Vue+Mocha單元測(cè)試基本配置完成,執(zhí)行test:unit 命令后隧枫,可在項(xiàng)目中查看測(cè)試效果

Vue & jest

項(xiàng)目創(chuàng)建

項(xiàng)目創(chuàng)建時(shí)選擇 Jest 的Unit Testing喉磁,具體操作可查看Mocha的創(chuàng)建

添加測(cè)試報(bào)告

安裝依賴(lài):

npm i --save-dev jest-html-reporter

配置jest.config.js

jest集成了測(cè)試所需的功能谓苟,包括斷言,覆蓋率协怒,以及測(cè)試報(bào)告等涝焙,測(cè)試配置文件如下:

module.exports = {
  preset: '@vue/cli-plugin-unit-jest',
  moduleFileExtensions: [
    'js',
    // 告訴 Jest 處理 `*.vue` 文件
    'vue'
  ],
  moduleNameMapper: {
    // 支持源代碼中相同的 `@` -> `src` 別名
    '^@/(.*)$': '<rootDir>/src/$1'
  },
  transform: {
    // 用 `babel-jest` 處理 `*.js` 文件
    '^.+\\.js$': '<rootDir>/node_modules/babel-jest',
    // 用 `vue-jest` 處理 `*.vue` 文件
    '.*\\.(vue)$': '<rootDir>/node_modules/vue-jest'
  },
  testMatch: ['**/__tests__/**/*.[jt]s?(x)', '**/?(*.)+(spec|test).[jt]s?(x)', '**/src/**/*.spec.{j,t}s?(x)'],
  snapshotSerializers: [
    // 快照的序列化工具
    '<rootDir>/node_modules/jest-serializer-vue'
  ],
  displayName: {
    name: 'CLIENT',
    color: 'blue'
  },
  // 成多種格式的測(cè)試覆蓋率報(bào)告  可選
  collectCoverage: true,
  collectCoverageFrom: ['**/*.{js,vue}', '!**/node_modules/**', '!**/dist/**', '!**/coverage/**'],
  // report配置
  reporters: [
    'default',
    [
      './node_modules/jest-html-reporter',
      {
        pageTitle: 'test report',
        outputPath: 'testReport/JesttestReport.html',
        includeFailureMsg: true
      }
    ]
  ]
}

至此,Vue+Jest單元測(cè)試基本配置完成孕暇,執(zhí)行test:unit 命令后仑撞,可在項(xiàng)目中查看測(cè)試效果。

Jest相對(duì)Mocha而言妖滔,配置簡(jiǎn)單許多隧哮,開(kāi)箱即用,考慮到不同的庫(kù)需要學(xué)習(xí)不同的API铛楣,踩坑的風(fēng)險(xiǎn)也隨之提升近迁,后續(xù)框架均只采用Jest進(jìn)行配置。

Angular

Angular腳手架在創(chuàng)建項(xiàng)目時(shí)自動(dòng)配置單元測(cè)試簸州,采用Karma和Jasmine鉴竭,引入Jest需要遷移

angular & Jest

配置時(shí)默認(rèn)使用angular腳手架創(chuàng)建的項(xiàng)目

遷移

第一步,下載相關(guān)的依賴(lài)包:

npm i --save-dev jest jest-preset-angular @types/jest jest-html-reporter

第二步岸浑,在pakage.json中對(duì)Jest進(jìn)行配置搏存,也可直接配置jest.config.js

"jest": {
  "preset": "jest-preset-angular",
  "setupFilesAfterEnv": ["<rootDir>/src/setupJest.ts"]
}

第三步,在src目錄下創(chuàng)建上一步中設(shè)置的 setup 文件setupJest.ts

import 'jest-preset-angular'; // jest 對(duì)于 angular 的預(yù)配置

接下來(lái)矢洲,我們就可以在 package.json 的 script 中配置 test 的命令了:

"test": "jest"

此時(shí)璧眠,在命令行中運(yùn)行測(cè)試命令,就應(yīng)該能夠順利把測(cè)試跑起來(lái)并通過(guò)了读虏。如果沒(méi)有通過(guò)责静,可能是因?yàn)槲覀冊(cè)?code>src/tsconfig.spec.json中的 file 配置中有test.ts的配置,這是 Karma 的 setup 文件盖桥,刪掉這行配置并刪除對(duì)應(yīng)的文件灾螃,(src/tsconfig.app.json中出現(xiàn)的test.ts也可一并刪除),重新執(zhí)行npm run test即可

刪除 Karma 相關(guān)代碼

  • 刪除相關(guān)依賴(lài)包(@types/jasmine @types/jasminewd2 jasmine-core jasmine-spec-reporter 因?yàn)樵?e2e 測(cè)試中有使用所以不能刪除):
    npm uninstall karma karma-chrome-launcher karma-coverage-istanbul-reporter karma-jasmine karma-jasmine-html-reporter
    
  • 刪除文件src/karma.config.js
  • 刪除 angular.json中test的配置
  • src/tsconfig.spec.jsoncompilerOptions.type的配置移除 jasmine, 加上 jest揩徊。

至此腰鬼,Jest測(cè)試環(huán)境就算順利搭建好了

React

Create React App創(chuàng)建后react項(xiàng)目后,是默認(rèn)集成Jest的塑荒,所以我們只需完善配置即可

淺層渲染

如果你希望測(cè)試獨(dú)立于它們渲染的子組件的組件熄赡,我們建議使用 Enzyme 的 shallow() 渲染API。

第一步齿税,安裝enzyme依賴(lài)

npm install --save-dev enzyme enzyme-adapter-react-16 react-test-renderer

第二步彼硫,修改src/setupTests.js

import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';

configure({ adapter: new Adapter() });

// 添加在測(cè)試中模擬的瀏覽器API
const localStorageMock = {
  getItem: jest.fn(),
  setItem: jest.fn(),
  removeItem: jest.fn(),
  clear: jest.fn(),
};
global.localStorage = localStorageMock;

覆蓋率報(bào)告

Jest 有一個(gè)集成的覆蓋率報(bào)告器,可以很好地與 ES6 配合使用,無(wú)需配置乌助。運(yùn)行 npm test -- --coverage

進(jìn)階學(xué)習(xí)文檔

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市他托,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌仆葡,老刑警劉巖赏参,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異沿盅,居然都是意外死亡把篓,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門(mén)腰涧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)韧掩,“玉大人,你說(shuō)我怎么就攤上這事窖铡×迫瘢” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵费彼,是天一觀的道長(zhǎng)滑臊。 經(jīng)常有香客問(wèn)我,道長(zhǎng)箍铲,這世上最難降的妖魔是什么雇卷? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮颠猴,結(jié)果婚禮上关划,老公的妹妹穿的比我還像新娘。我一直安慰自己翘瓮,他們只是感情好贮折,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著春畔,像睡著了一般脱货。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上律姨,一...
    開(kāi)封第一講書(shū)人閱讀 49,166評(píng)論 1 284
  • 那天振峻,我揣著相機(jī)與錄音,去河邊找鬼择份。 笑死扣孟,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的荣赶。 我是一名探鬼主播凤价,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼鸽斟,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了利诺?” 一聲冷哼從身側(cè)響起富蓄,我...
    開(kāi)封第一講書(shū)人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎慢逾,沒(méi)想到半個(gè)月后立倍,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡侣滩,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年口注,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片君珠。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡寝志,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出策添,到底是詐尸還是另有隱情材部,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布舰攒,位于F島的核電站败富,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏摩窃。R本人自食惡果不足惜兽叮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望猾愿。 院中可真熱鬧鹦聪,春花似錦、人聲如沸蒂秘。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)姻僧。三九已至规丽,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間撇贺,已是汗流浹背赌莺。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留松嘶,地道東北人艘狭。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親巢音。 傳聞我的和親對(duì)象是個(gè)殘疾皇子遵倦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344