隨着每一個工程的複雜化、代碼的高複用性要求和前端代碼模塊之間的高內聚低耦合的需求,前端工程中的單元測試流程就顯得頗有其必要。html
首先咱們要明確測試是什麼:前端
爲檢測特定的目標是否符合標準而採用專用的工具或者方法進行驗證,並最終得出特定的結果。node
對於前端開發過程來講,這裏的特定目標就是指咱們寫的代碼,而工具就是咱們須要用到的測試框架(庫)、測試用例等。檢測處的結果就是展現測試是否經過或者給出測試報告,這樣才能方便問題的排查和後期的修正。git
基於測試「是什麼」的說法,爲便於剛從事前端開發的同行的進階理解,那咱們就列出單元測試它「不是什麼」:github
須要訪問數據庫的測試不是單元測試面試
須要訪問網絡的測試不是單元測試chrome
須要訪問文件系統的測試不是單元測試數據庫
--- 修改代碼的藝術npm
對於單元測試「不是什麼」的引用解釋,至此點到爲止。鑑於篇幅限制,對於引用內容,我想前端開發的同行們看到後會初步有一個屬於本身的理解。api
對於如今的前端工程,一個標準完整的項目,測試是很是有必要的。不少時候咱們只是完成了項目而忽略了項目測試的部分,測試的意義主要在於下面幾點:
在單元測試中,經常使用的方法論有兩個:TDD(測試驅動開發)&BDD(行爲驅動開發)
TDD(Test-driven development):
其基本思路是經過測試來推進整個開發的進行。
單元測試的首要目的不是爲了可以編寫出大覆蓋率的所有經過的測試代碼,而是須要從使用者(調用者)的角度出發,嘗試函數邏輯的各類可能性,進而輔助性加強代碼質量
測試是手段而不是目的。測試的主要目的不是證實代碼正確,而是幫助發現錯誤,包括低級的錯誤
測試要快。快速運行、快速編寫
測試代碼保持簡潔
不會忽略失敗的測試。一旦團隊開始接受1個測試的構建失敗,那麼他們漸漸地適應二、三、4或者更多的失敗。在這種狀況下,測試集就再也不起做用
須要注意的是:
必定不能誤解了TDD的核心目的!
測試不是爲了覆蓋率和正確率
而是做爲實例,告訴開發人員要編寫什麼代碼
紅燈(代碼還不完善,測試掛)-> 綠燈(編寫代碼,測試經過)-> 重構(優化代碼並保證測試經過)
TDD的過程是:
需求分析,思考實現。考慮如何「使用」產品代碼,是一個實例方法仍是一個類方法,是從構造函數傳參仍是從方法調用傳參,方法的命名,返回值等。這時其實就是在作設計,並且設計以代碼來體現。此時測試爲紅
實現代碼讓測試爲」綠燈「
重構,而後重複測試
最終符合全部要求即:
每一個概念都被清晰的表達
代碼中無自我重複
沒有多餘的東西
經過測試
行爲驅動開發(BDD),重點是經過與利益相關者(簡單說就是客戶)的討論,取得對預期的軟件行爲的認識,其重點在於溝通
BDD過程是:
從業務的角度定義具體的,以及可衡量的目標
找到一種能夠達到設定目標的、對業務最重要的那些功能的方法
而後像故事同樣描述出一個個具體可執行的行爲。其描述方法基於一些通用詞彙,這些詞彙具備準確無誤的表達能力和一致的含義。例如,expect
, should
, assert
尋找合適語言及方法,對行爲進行實現
測試人員檢驗產品運行結果是否符合預期行爲。最大程度的交付出符合用戶指望的產品,避免表達不一致帶來的問題
以上內容從什麼是單元測試談到單元測試的方法論。那麼怎樣用經常使用框架進行單元測試?單元測試的工具環境是什麼?單元測試的實際示例是怎樣的?
首先應該簡單介紹一下Mocha、Karma和Travis.CI
Mocha:mocha 是一個功能豐富的前端測試框架。所謂"測試框架",就是運行測試的工具。經過它,能夠爲JavaScript應用添加測試,從而保證代碼的質量。mocha 既能夠基於 Node.js 環境運行 也能夠在瀏覽器環境運行。
Karma:一個基於Node.js的JavaScript測試執行過程管理工具(Test Runner)。該工具可用於測試全部主流Web瀏覽器,也可集成到CI(Continuous integration)工具,也可和其餘代碼編輯器一塊兒使用。這個測試工具的一個強大特性就是,它能夠監控文件的變化,而後自行執行,經過console.log顯示測試結果。Karma的一個強大特性就是,它能夠監控一套文件的變換,並當即開始測試已保存的文件,用戶無需離開文本編輯器。測試結果一般顯示在命令行中,而非代碼編輯器。這也就讓 Karma 基本能夠和任何 JS 編輯器一塊兒使用。
Travis.CI:提供的是持續集成服務(Continuous Integration,簡稱 CI)。它綁定 Github 上面的項目,只要有新的代碼,就會自動抓取。而後,提供一個運行環境,執行測試,完成構建,還能部署到服務器。
持續集成指的是隻要代碼有變動,就自動運行構建和測試,反饋運行結果。確保符合預期之後,再將新代碼"集成"到主幹。
持續集成的好處在於,每次代碼的小幅變動,就能看到運行結果,從而不斷累積小的變動,而不是在開發週期結束時,一會兒合併一大塊代碼。
斷言庫
基本工具框架介紹完畢後,相信稍微瞭解點測試的同行都知道,作單元測試是須要寫測試腳本的,那麼測試腳本就須要用到斷言庫。」斷言「,我的理解即爲」用彼代碼判定測試此代碼的正確性,檢驗並暴露此代碼的錯誤。「那麼對於前端單元測試來講,有如下經常使用斷言庫:
看一段代碼示例:
expect(add(1, 1)).to.be.equal(2);
這是一句斷言代碼。
所謂"斷言",就是判斷源碼的實際執行結果與預期結果是否一致,若是不一致就拋出一個錯誤。上面這句斷言的意思是,調用 add(1, 1),結果應該等於 2。全部的測試用例(it 塊)都應該含有一句或多句的斷言。它是編寫測試用例的關鍵。斷言功能由斷言庫來實現,Mocha 自己不帶斷言庫,因此必須先引入斷言庫。
引入斷言庫代碼示例:
var expect = require('chai').expect;
斷言庫有不少種,Mocha 並不限制使用哪種,它容許你使用你想要的任何斷言庫。上面代碼引入的斷言庫是 chai,而且指定使用它的 expect 斷言風格。下面這些常見的斷言庫:
此處主要介紹一下node assert中經常使用的API
斷言 value 的值是否爲true,這裏的等於判斷使用的是 == 而不是 ===。message 是斷言描述,爲可選參數。
const assert = require('assert'); assert(true);
使用方法同 assert(value[, message])
。
預期 actual 與 expect值相等。equal用於比較的 actual 和 expect 是基礎類型(string, number, boolearn, null, undefined)的數據。其中的比較使用的是 == 而不是 ===。
it('assert.equal', () => { assert.equal(null, false, 'null compare with false'); // 報錯 assert.equal(null, true, 'null compare with true'); // 報錯 assert.equal(undefined, false, 'undefined compare with false'); // 報錯 assert.equal(undefined, true, 'undefined compare with true'); // 報錯 assert.equal('', false, '"" compare with false'); // 正常 })
用法同 assert.equal(actual, expect[, message])
只是對預期結果取反(即不等於)。
用法同 assert.equal(actual, expect[, message])
可是內部比較是使用的是 === 而不是 ==。
用法同 assert.strictEqual(actual, expect[, message])
只是對預期結果取反(即不嚴格等於)。
it('assert.strictEqual', () => { assert.strictEqual('', false); // 報錯 })
deepEqual 方法用於比較兩個對象。比較的過程是比較兩個對象的 key 和 value 值是否相同, 比較時用的是 == 而不是 ===。
it('assert.deepEqual', () => { const a = { v: 'value' }; const b = { v: 'value' }; assert.deepEqual(a, b); })
用法同 assert.deepEqual(actual, expect[, message])
只是對預期結果取反(即不嚴格深等於)。
用法同 assert.deepEqual(actual, expect[, message])
可是內部比較是使用的是 === 而不是 ==。
用法同 assert.deepStrictEqual(actual, expect[, message])
只是對結果取反(即不嚴格深等於)。
錯誤斷言與捕獲, 斷言指定代碼塊運行必定會報錯或拋出錯誤。若代碼運行未出現錯誤則會斷言失敗,斷言異常。
it('throws', () => { var fun = function() { xxx }; assert.throws(fun, 'fun error'); })
錯誤斷言與捕獲, 用法同 throws 相似,只是和 throws 預期結果相反。斷言指定代碼塊運行必定不會報錯或拋出錯誤。若代碼運行出現錯誤則會斷言失敗,斷言異常。
it('throws', () => { var fun = function() { xxx }; assert.doesNotThrow(fun, 'fun error'); })
npm install mocha -g
固然也能夠在不在全局安裝,只安局部安裝在項目中
npm install mocha --save
test.js
var assert = require('assert') describe('Array', function() { describe('#indexOf()', function() { it('should return -1 when the value is not present', function() { assert.equal(-1, [1, 2, 3].indexOf(-1)) }) }) })
這段文件和簡單就是測試 Array
的一個 indexOf()
方法。這裏我是用的斷言庫是 Node 所提供的 Assert
模塊裏的API。這裏斷言 -1 等於 數組 [1, 2, 3]
執行 indexOf(-1)
後返回的值,若是測試經過則不會報錯,若是有誤就會報出錯誤。
下面咱們使用全局安裝的 mocha
來運行一下這個文件 mocha test.js
。
下面是返回結果
基礎測試用例實例
const assert = require('assert'); describe('測試套件描述', function() { it('測試用例描述: 1 + 2 = 3', function() { // 測試代碼 const result = 1 + 2; // 測試斷言 assert.equal(result, 3); }); });
Mocha 測試用例主要包含下面幾部分:
說明:每一個測試文件中能夠有多個測試套件和測試用例。mocha不只能夠在node環境運行, 也能夠在瀏覽器環境運行;在node中運行也能夠經過npm i mocha -g
全局安裝mocha而後以命令行的方式運行測試用例也是可行的。
這裏略微詳細介紹下測試腳本寫法
Mocha 的做用是運行測試腳本,首先必須學會寫測試腳本。所謂"測試腳本",就是用來測試源碼的腳本。下面是一個加法模塊 add.js 的代碼。
// add.js function add(x, y) { return x + y; } module.exports = add;
要測試這個加法模塊是否正確,就要寫測試腳本。一般,測試腳本與所要測試的源碼腳本同名,可是後綴名爲.test.js(表示測試)或者.spec.js(表示規格)。好比,add.js 的測試腳本名字就是 add.test.js。
// add.test.js var add = require('./add.js'); var expect = require('chai').expect; describe('加法函數的測試', function() { it('1 加 1 應該等於 2', function() { expect(add(1, 1)).to.be.equal(2); }); });
上面這段代碼,就是測試腳本,它能夠獨立執行。測試腳本里面應該包括一個或多個 describe 塊,每一個 describe 塊應該包括一個或多個 it 塊。
describe 塊稱爲"測試套件"(test suite),表示一組相關的測試。它是一個函數,第一個參數是測試套件的名稱("加法函數的測試"),第二個參數是一個實際執行的函數。
it 塊稱爲"測試用例"(test case),表示一個單獨的測試,是測試的最小單位。它也是一個函數,第一個參數是測試用例的名稱("1 加 1 應該等於 2"),第二個參數是一個實際執行的函數。
expect 斷言的優勢是很接近天然語言,下面是一些例子。
// 相等或不相等 expect(4 + 5).to.be.equal(9); expect(4 + 5).to.be.not.equal(10); expect(foo).to.be.deep.equal({ bar: 'baz' }); // 布爾值爲true expect('everthing').to.be.ok; expect(false).to.not.be.ok; // typeof expect('test').to.be.a('string'); expect({ foo: 'bar' }).to.be.an('object'); expect(foo).to.be.an.instanceof(Foo); // include expect([1, 2, 3]).to.include(2); expect('foobar').to.contain('foo'); expect({ foo: 'bar', hello: 'universe' }).to.include.keys('foo'); // empty expect([]).to.be.empty; expect('').to.be.empty; expect({}).to.be.empty; // match expect('foobar').to.match(/^foo/);
基本上,expect 斷言的寫法都是同樣的。頭部是 expect 方法,尾部是斷言方法,好比 equal、a/an、ok、match 等。二者之間使用 to 或 to.be 鏈接。若是 expect 斷言不成立,就會拋出一個錯誤。事實上,只要不拋出錯誤,測試用例就算經過。
it('1 加 1 應該等於 2', function() {});
上面的這個測試用例,內部沒有任何代碼,因爲沒有拋出了錯誤,因此仍是會經過。
基於 karma 測試經常使用的一些模塊
# 基礎測試庫 npm install karma-cli -g npm install karma mocha karma-mocha --save-dev # 斷言庫 npm install should --save-dev npm install karma-chai --save-dev # 瀏覽器相關 npm install karma-firefox-launcher --save-dev npm install karma-chrome-launcher --save-dev
若是對軟件測試、接口測試、自動化測試、面試經驗交流。感興趣能夠加軟件測試交流:1085991341,還會有同行一塊兒技術交流。
這裏的配置主要關注的是karma.conf.js
的相關配置。若是要使用 karma 和 mocha 最好經過npm install karma-cli -g
全局安裝karma-cli
。
須要注意的兩個字段:
NODE_ENV
變量。--no-sandbox
模式。{ "browsers": ["Chrome", "ChromeHeadless", "ChromeHeadlessNoSandbox"], "customLaunchers": { "ChromeHeadlessNoSandbox": { "base": "ChromeHeadless", "flags": ["--no-sandbox"] } } }
或者
{ "browsers": ["Chrome_travis_ci"], "customLaunchers": { "Chrome_travis_ci": { "base": "Chrome", "flags": ["--no-sandbox"] } } }
mocha
來測試完成的求和方法。下面是項目結構,項目建立完成後經過 npm i mocha -D
安裝 mocha
模塊。而後在本地運行 npm test
看是否可以測試經過。若是可以測試經過則說明咱們的能夠繼續下一步了。
建立 travis-ci 配置文件 .travis.yml
, 文件內容。
language: node_js node_js: - "node" - "8.9.4"
至此基本完成了項目開發和測試代碼編寫的過程,下一步就能夠接入 travis-ci 測試了。
經過GitHub登陸 travis-ci 的官網
找到GitHub上剛纔建立的須要測試的項目,並開啓測試
查看測試過程,及時發現問題。
查看測試狀態是否經過測試,若是未經過及時排查問題反覆修改;若是經過能夠在項目文檔中添加一個測試經過的標識。
以上內容就是本篇的所有內容,以上內容但願對你有幫助,有被幫助到的朋友歡迎點贊,評論。