摘要:為保證代碼的質(zhì)量,單元測(cè)試必不可少。本文記錄自己在學(xué)習(xí)單元測(cè)試過程中的一些總結(jié)。以一個(gè)項(xiàng)目為例,代碼結(jié)構(gòu)如下前端測(cè)試框架主要是與,這里我們選擇,斷言庫(kù)有以及自帶的。
為保證代碼的質(zhì)量,單元測(cè)試必不可少。本文記錄自己在學(xué)習(xí)單元測(cè)試過程中的一些總結(jié)。
TDD與BDD的區(qū)別TDD屬于測(cè)試驅(qū)動(dòng)開發(fā),BDD屬于行為驅(qū)動(dòng)開發(fā)。個(gè)人理解其實(shí)就是TDD先寫測(cè)試模塊,再寫主功能代碼,然后能讓測(cè)試模塊通過測(cè)試,而BDD是先寫主功能模塊,z再寫測(cè)試模塊。詳見示例
服務(wù)端代碼測(cè)試所謂服務(wù)端代碼,指的就是一個(gè)node的模塊,能在node的環(huán)境中運(yùn)行。以一個(gè)項(xiàng)目為例,代碼結(jié)構(gòu)如下:
. ├── index.js ├── node_modules ├── package.json └── test └── test.js
前端測(cè)試框架主要是Mocha與Jasmine,這里我們選擇Mocha,斷言庫(kù)有should、expect、chai以及node自帶的assert。這里我們選擇chai,chai中包含了expect、should及assert的書寫風(fēng)格。
npm install mocha chai --save-dev
index.js
const getNum = (value) => { return value * 2 } module.exports = getNum
test.js
const chai = require("chai") const expect = chai.expect const getNum = require("../index") describe("Test", function() { it("should return 20 when the value is 10", function() { expect(getNum(10)).to.equal(20) }) })
describe用于給測(cè)試用例分組,it代表一個(gè)測(cè)試用例。
package.json
"scripts": { "test": "mocha" }
?需要在全局下安裝Mocha
npm install mocha -g
項(xiàng)目目錄下執(zhí)行
npm run test
測(cè)試通過
完成代碼測(cè)試之后我們?cè)偃タ纯创a測(cè)試的覆蓋率。測(cè)試代碼覆蓋率我們選擇使用istanbul,全局安裝
npm install -g istanbul
使用istanbul啟動(dòng)Mocha
istanbul cover _mocha
測(cè)試通過,覆蓋率100%
行覆蓋率(line coverage):是否每一行都執(zhí)行了?
函數(shù)覆蓋率(function coverage):是否每個(gè)函數(shù)都調(diào)用了?
分支覆蓋率(branch coverage):是否每個(gè)if代碼塊都執(zhí)行了?
語句覆蓋率(statement coverage):是否每個(gè)語句都執(zhí)行了?
修改index.js再看代碼覆蓋率
const getNum = (value) => { if(value === 0) { return 1 }else { return value * 2 } } module.exports = getNum
發(fā)現(xiàn)代碼覆蓋率發(fā)生了變化
修改test.js添加測(cè)試用例
describe("Test", function() { it("should return 20 when the value is 10", function() { expect(getNum(10)).to.equal(20) }) it("should return 1 when the value is 0", function() { expect(getNum(0)).to.equal(0) }) })
代碼覆蓋率又回到了100%
客戶端代碼客戶端代碼即運(yùn)行在瀏覽器中的代碼,代碼中包含了window、document等對(duì)象,需要在瀏覽器環(huán)境下才能起作用。還是以一個(gè)項(xiàng)目為例,代碼結(jié)構(gòu)如下:
. ├── index.js ├── node_modules ├── package.json └── test └── test.js └── test.html
我們依然使用Mocha測(cè)試庫(kù)及chai斷言庫(kù)。
npm install mocha chai --save-dev
index.js
window.createDiv = function(value) { var oDiv = document.createElement("div") oDiv.id = "myDiv" oDiv.innerHTML = value document.body.appendChild(oDiv) }
test.js
mocha.ui("bdd") var expect = chai.expect describe("Tests", function () { before(function () { createDiv("test") }) it("content right", function () { var el = document.querySelector("#myDiv") expect(el).to.not.equal(null) expect(el.innerHTML).to.equal("test") }) }) mocha.run()
test.html
Tests
直接用瀏覽器打開test.html文件便能看到測(cè)試結(jié)果
當(dāng)然我們可以選擇PhantomJS模擬瀏覽器去做測(cè)試,這里我們使用mocha-phantomjs對(duì)test.html做測(cè)試。
全局安裝mocha-phantomjs
npm install mocha-phantomjs -g
修改package.json
"scripts": { "test": "mocha-phantomjs test/test.html" }
項(xiàng)目目錄下執(zhí)行
npm run test
mocha-phantomjs在mac下執(zhí)行會(huì)報(bào)phantomjs terminated with signal SIGSEGV,暫時(shí)沒有找到什么解決方案。所以我在ubuntu下執(zhí)行,結(jié)果顯示如圖
上述方式雖然能完成代碼的單元測(cè)試,但是要完成代碼覆蓋率的計(jì)算也沒有什么好的方式,所以我選擇引入測(cè)試管理工具karma
karma使用指南略去一大堆介紹karma的廢話,項(xiàng)目下引入karma
npm install karma --save-dev
初始化配置karma配置文件
npm install karma -g karma init
使用karma默認(rèn)配置看看每一項(xiàng)的作用
Karma.conf.js
module.exports = function(config) { config.set({ basePath: "", // 設(shè)置根目錄 frameworks: ["jasmine"], // 測(cè)試框架 files: [ // 瀏覽器中加載的文件 ], exclude: [ // 瀏覽器中加載的文件中排除的文件 ], preprocessors: { // 預(yù)處理 }, reporters: ["progress"], // 添加額外的插件 port: 9876, // 開啟測(cè)試服務(wù)時(shí)監(jiān)聽的端口 colors: true, logLevel: config.LOG_INFO, autoWatch: true, // 監(jiān)聽文件變化,發(fā)生變化則重新編譯 browsers: ["Chrome"], // 測(cè)試的瀏覽器 singleRun: false, // 執(zhí)行測(cè)試用例后是否關(guān)閉測(cè)試服務(wù) concurrency: Infinity }) }
此時(shí)的項(xiàng)目結(jié)構(gòu)如下所示
. ├── index.js ├── node_modules ├── package.json ├── karma.conf.js └── test └── test.js
首先我們將測(cè)試框架jasmine改為我們熟悉的mocha及chai,添加files及plugins
npm install karma karma-mocha karma-chai mocha chai karma-chrome-launcher --save-dev
karma.conf.js
module.exports = function(config) { config.set({ basePath: "", frameworks: ["mocha", "chai"], files: [ "index.js", "test/*.js" ], exclude: [ ], preprocessors: { }, reporters: ["progress"], port: 9876, colors: true, logLevel: config.LOG_INFO, autoWatch: true, browsers: ["Chrome"], singleRun: false, concurrency: Infinity, plugins: [ "karma-chrome-launcher", "karma-mocha", "karma-chai", ] }) }
全局安裝karma-cli
npm install -g karma-cli
修改package.json
"scripts": { "test": "karma start karma.conf.js" }
執(zhí)行npm run test便可以啟用chrome去加載頁(yè)面。
karma測(cè)試代碼覆蓋率測(cè)試代碼覆蓋率,我們還是選擇使用PhantomJS模擬瀏覽器,將singleRun設(shè)為true,即執(zhí)行完測(cè)試用例就退出測(cè)試服務(wù)。
npm install karma-phantomjs-launcher --save-dev
將browsers中的Chrome改為PhantomJS,plugins中的karma-chrome-launcher改為karma-phantomjs-launcher
執(zhí)行npm run test ,測(cè)試通過且自動(dòng)退出如圖所示
引入karma代碼覆蓋率模塊karma-coverage,改模塊依賴于istanbul
npm install istanbul karma-coverage --save-dev
修改karma.conf.js
module.exports = function(config) { config.set({ basePath: "", frameworks: ["mocha", "chai"], files: [ "index.js", "test/*.js" ], exclude: [ ], preprocessors: { "index.js": ["coverage"] }, reporters: ["progress", "coverage"], port: 9876, colors: true, logLevel: config.LOG_INFO, autoWatch: true, browsers: ["PhantomJS"], singleRun: true, concurrency: Infinity, coverageReporter: { type : "text-summary" }, plugins: [ "karma-phantomjs-launcher", "karma-mocha", "karma-coverage", "karma-chai", ] }) }
對(duì)index.js文件使用coverage進(jìn)行預(yù)處理,加入karma-coverage插件,覆蓋率測(cè)試輸出coverageReporter配置,詳見這里這里為了方便截圖顯示將其設(shè)為text-summary
執(zhí)行npm run test,顯示結(jié)果如下圖所示
ES6代碼覆蓋率計(jì)算目前的瀏覽器并不能兼容所有ES6代碼,所以ES6代碼都需要經(jīng)過babel編譯后才可在瀏覽器環(huán)境中運(yùn)行,但編譯后的代碼webpack會(huì)加入許多其他的模塊,對(duì)編譯后的代碼做測(cè)試覆蓋率就沒什么意義了。
index.js
const createDiv = value => { var oDiv = document.createElement("div") oDiv.id = "myDiv" oDiv.innerHTML = value document.body.appendChild(oDiv) } module.exports = createDiv
我們使用ES6中的箭頭函數(shù)
test.js
const createDiv = require("../index") describe("Tests", function () { before(function () { createDiv("test") }) it("content right", function () { var el = document.querySelector("#myDiv") expect(el).to.not.equal(null) expect(el.innerHTML).to.equal("test") }) })
kama.conf.js
module.exports = function(config) { config.set({ basePath: "", frameworks: ["mocha", "chai"], files: [ "test/*.js" ], exclude: [ ], preprocessors: { "index.js": ["coverage"], "test/*.js": ["webpack"] }, reporters: ["progress", "coverage"], port: 9876, colors: true, logLevel: config.LOG_INFO, autoWatch: true, browsers: ["PhantomJS"], singleRun: true, concurrency: Infinity, coverageReporter: { type : "text-summary" }, webpack: { module: { rules: [ { test: /.js$/, exclude: /node_modules/, use: { loader: "babel-loader", options: { "presets": ["es2015"], "plugins": [["istanbul"]] } } } ] } }, plugins: [ "karma-phantomjs-launcher", "karma-mocha", "karma-coverage", "karma-webpack", "karma-chai", ] }) }
test.js文件通過require引入index.js文件,所以files只需引入test.js文件,再對(duì)test.js做webpack預(yù)處理。
需要相關(guān)的babel,webpack,karma依賴如下:
"devDependencies": { "babel-core": "^6.26.0", "babel-loader": "^7.1.2", "babel-plugin-istanbul": "^4.1.5", "babel-preset-es2015": "^6.24.1", "chai": "^4.1.2", "istanbul": "^0.4.5", "karma": "^2.0.0", "karma-chai": "^0.1.0", "karma-coverage": "^1.1.1", "karma-mocha": "^1.3.0", "karma-phantomjs-launcher": "^1.0.4", "karma-webpack": "^2.0.9", "mocha": "^4.1.0", "webpack": "^3.10.0" }
執(zhí)行npm run dev顯示如圖所示
travisCI及coverallstravisCI的配置這里不做詳解,我們將通過代碼測(cè)試覆蓋率上傳到coveralls獲取一個(gè)covarage的icon。
如果你是服務(wù)端代碼使用istanbul計(jì)算代碼覆蓋率的
.travis.yml
language: node_js node_js: - "stable" - 8 branches: only: - master install: - npm install script: - npm test after_script: "npm install coveralls && cat ./coverage/lcov.info | coveralls"
如果你是服務(wù)端代碼使用karma計(jì)算代碼覆蓋率的,則需使用coveralls模塊
npm install coveralls karma-coveralls --save-dev
Karma.conf.js
// Karma configuration module.exports = function(config) { config.set({ basePath: "", frameworks: ["mocha", "chai"], files: [ "test/*.js" ], exclude: [], preprocessors: { "test/*.js": ["webpack"], "index.js": ["coverage"] }, reporters: ["progress", "coverage", "coveralls"], port: 9876, colors: true, logLevel: config.LOG_INFO, autoWatch: true, browsers: ["PhantomJS"], singleRun: true, concurrency: Infinity, webpack: { module: { rules: [ { test: /.js$/, exclude: /node_modules/, use: { loader: "babel-loader", options: { "presets": ["es2015"], "plugins": [["istanbul"], ["transform-runtime"]] } } } ] } }, coverageReporter: { type : "lcov", dir : "coverage/" }, plugins: [ "karma-webpack", "karma-phantomjs-launcher", "karma-coverage", "karma-mocha", "karma-chai", "karma-coveralls" ], }) }
plugins添加karma-coveralls,reporters添加coveralls,coverageReporter輸出配置改為lcov。
可以參考我自己實(shí)現(xiàn)的一個(gè)show-toast庫(kù)
參考https://github.com/tmallfe/tm...
https://codeutopia.net/blog/2...
https://github.com/jdavis/tdd...
https://jasmine.github.io/
https://github.com/bbraithwai...
https://mochajs.org/
https://toutiao.io/posts/5649...
https://coveralls.io/
https://karma-runner.github.i...
https://github.com/karma-runn...
https://shouldjs.github.io/
https://juejin.im/post/598073...
http://www.bradoncode.com/blo...
http://docs.casperjs.org/en/l...
https://github.com/gotwarlost...
https://www.jianshu.com/p/ffd...
http://www.bijishequ.com/deta...
http://phantomjs.org/
https://github.com/CurtisHump...
http://www.jackpu.com/shi-yon...
https://github.com/JackPu/Jav...
https://github.com/caitp/karm...
https://github.com/karma-runn...
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/93051.html
摘要:測(cè)試光譜光譜的一端單元測(cè)試顧名思義,代碼以單元為單位進(jìn)行測(cè)試。這個(gè)系列文章整體如下測(cè)試你的前端代碼單元測(cè)試測(cè)試你的前端代碼端到端測(cè)試測(cè)試你的前端代碼集成測(cè)試。 showImg(https://segmentfault.com/img/remote/1460000008812278?w=998&h=354); 本文作者:Gil Tayar 編譯:胡子大哈 翻譯原文:http://hu...
摘要:測(cè)試光譜光譜的一端單元測(cè)試顧名思義,代碼以單元為單位進(jìn)行測(cè)試。這個(gè)系列文章整體如下測(cè)試你的前端代碼單元測(cè)試測(cè)試你的前端代碼端到端測(cè)試測(cè)試你的前端代碼集成測(cè)試。 showImg(https://segmentfault.com/img/remote/1460000008812278?w=998&h=354); 本文作者:Gil Tayar 編譯:胡子大哈 翻譯原文:http://hu...
摘要:而測(cè)試驅(qū)動(dòng)開發(fā)技術(shù)并不只是單純的測(cè)試工作。需求向來就是軟件開發(fā)過程中感覺最不好明確描述易變的東西。這里說的需求不只是指用戶的需求,還包括對(duì)代碼 可能很多人和我一樣, 首次聽到前端架構(gòu)這個(gè)詞, 第一反應(yīng)是: 前端還有架構(gòu)這一說呢? 在后端開發(fā)領(lǐng)域, 系統(tǒng)規(guī)劃和可擴(kuò)展性非常關(guān)鍵, 因此架構(gòu)師備受重視, 早在開發(fā)工作啟動(dòng)之前, 他們就被邀請(qǐng)加入到項(xiàng)目中, 而且他們會(huì)跟客戶討論即將建成的平臺(tái)的...
摘要:而測(cè)試驅(qū)動(dòng)開發(fā)技術(shù)并不只是單純的測(cè)試工作。需求向來就是軟件開發(fā)過程中感覺最不好明確描述易變的東西。這里說的需求不只是指用戶的需求,還包括對(duì)代碼 可能很多人和我一樣, 首次聽到前端架構(gòu)這個(gè)詞, 第一反應(yīng)是: 前端還有架構(gòu)這一說呢? 在后端開發(fā)領(lǐng)域, 系統(tǒng)規(guī)劃和可擴(kuò)展性非常關(guān)鍵, 因此架構(gòu)師備受重視, 早在開發(fā)工作啟動(dòng)之前, 他們就被邀請(qǐng)加入到項(xiàng)目中, 而且他們會(huì)跟客戶討論即將建成的平臺(tái)的...
摘要:?jiǎn)卧獪y(cè)試上一節(jié)有討論過,單元測(cè)試就是以代碼單元為單位進(jìn)行測(cè)試,代碼單元可以是一個(gè)函數(shù),一個(gè)模塊,或者一個(gè)類。單元測(cè)試是最容易理解也最容易實(shí)現(xiàn)的測(cè)試方式。在寫單元測(cè)試的時(shí)候,盡量將你的單元測(cè)試獨(dú)立出來,不要幾個(gè)單元互相引用。 showImg(https://segmentfault.com/img/remote/1460000008823416?w=997&h=350); 本文作者:G...
閱讀 799·2021-11-12 10:36
閱讀 3382·2021-09-08 10:44
閱讀 2748·2019-08-30 11:08
閱讀 1407·2019-08-29 16:12
閱讀 2677·2019-08-29 12:24
閱讀 901·2019-08-26 10:14
閱讀 686·2019-08-23 18:32
閱讀 1176·2019-08-23 17:52