前言
在前端開發中,測試常常是被忽略的一環。因此最近在研究前端自動化測試框架Karma,把個人的學習過程分享出來,希望對大家有幫助。
什麼是Karma?
Karma是由Google團隊開發的一套前端測試執行框架。它不同於測試框架(例如jasmine,mocha等),執行在這些測試框架之上。主要完成一下工作:
- Karma啟動一個web伺服器,生成包含js原始碼和js測試指令碼的頁面;
- 執行瀏覽器載入頁面,並顯示測試的結果;
- 如果開啟檢測,則當檔案有修改時,執行繼續執行以上過程。
Karma的安裝配置
初始專案結構
1 2 3 4 5 |
karma-example ├── src ├── index.js ├── test ├── package.json |
index.js的內容如下
1 2 3 4 5 6 7 |
function isNum(num) { if (typeof num === 'number') { return true } else { return false } } |
安裝Karma環境
為了方便搭建Karma環境,我們可以全域性安裝karma-cli
來幫我們初始化測試環境:
1 |
npm i -g karma-cli |
然後在專案中安裝karma包
1 |
npm i --save-dev karma |
接下來在工程目錄中執行karma init
來進行測試環境初始化,並按照指示一步步完成。
上圖是選項的示例,這裡使用jasmine測試框架,PhantomJS作為程式碼執行的環境(也可以選擇其他瀏覽器作為執行環境,比如Chrome,IE等)。最後在專案中生成karma.conf.js檔案。
至此就搭建好了基本的Karma執行環境。
執行Karma
在test目錄裡編寫一個簡單的測試指令碼,我們使用的是jasmine測試框架,具體的api可以參考jasmine api,內容如下
1 2 3 4 5 6 |
describe('index.js: ', function() { it('isNum() should work fine.', function() { expect(isNum(1)).toBe(true) expect(isNum('1')).toBe(false) }) }) |
然後在專案根目錄下執行karma start
命令,我們可以看到執行的結果如下
可以看到,執行的結果顯示測試成功。
同時,因為我們之前設定了監控檔案的修改,所以當我們修改原始檔或者測試指令碼的時候,Karma會自動幫我們再次執行,無需我們手動操作。
Coverage
如何衡量測試指令碼的質量呢?其中一個參考指標就是程式碼覆蓋率(coverage)。
什麼是程式碼覆蓋率?簡而言之就是測試中執行到的程式碼佔所有程式碼的比率。其中又可以分為行數覆蓋率,分支覆蓋率等。具體的含義不再細說,有興趣的可以自行查閱資料。
雖然並不是說程式碼覆蓋率越高,測試的指令碼寫得越好(可以看看參考文獻4),但是程式碼覆蓋率對撰寫測試指令碼還是有一定的指導意義的。因此接下來我們在Karma環境中新增Coverage。
首先安裝好Karma覆蓋率工具
1 |
npm i --save-dev karma-coverage |
然後修改配置檔案karma.conf.js,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
module.exports = function(config) { config.set({ basePath: '', frameworks: ['jasmine'], files: [ 'src/**/*.js', 'test/**/*.js' ], exclude: [], // modified preprocessors: { 'src/**/*.js': ['coverage'] }, //modified reporters: ['progress', 'coverage'], // add coverageReporter: { type : 'html', dir : 'coverage/' }, port: 9876, colors: true, logLevel: config.LOG_INFO, autoWatch: true, browsers: ['PhantomJS'], singleRun: false, concurrency: Infinity }) } |
再執行karma start
後,會在目錄下生成coverage目錄,裡面有本次測試的覆蓋報告。開啟後的結果如下
使用Webpack+Babel
在實際專案中,有事會需要用到Webpack和ES6,所以接下來將Webpack和Babel整合進Karma環境中。
安裝karma-webpack
1 |
npm i --save-dev karma-webpack |
安裝babel
1 |
npm i --save-dev babel-loader babel-core babel-preset-es2015 |
然後檔案進行改造,src/index.js
檔案修改為
1 2 3 4 5 6 7 8 9 |
function isNum(num) { if (typeof num === 'number') { return true } else { return false } } exports.isNum = isNum |
text/index.js
檔案修改為
1 2 3 4 5 6 7 8 |
const Util = require('../src/index') describe('index.js: ', () => { it('isNum() should work fine.', () => { expect(Util.isNum(1)).toBe(true) expect(Util.isNum('1')).toBe(false) }) }) |
接下來修改配置檔案karma.conf.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
module.exports = function(config) { config.set({ basePath: '', frameworks: ['jasmine'], files: [ 'test/**/*.js' ], exclude: [], preprocessors: { 'test/**/*.js': ['webpack', 'coverage'] }, reporters: ['progress', 'coverage'], coverageReporter: { type: 'html', dir: 'coverage/' }, port: 9876, colors: true, logLevel: config.LOG_INFO, autoWatch: true, browsers: ['PhantomJS'], singleRun: false, concurrency: Infinity, webpack: { module: { loaders: [{ test: /\.js$/, loader: 'babel', exclude: /node_modules/, query: { presets: ['es2015'] } }] } } }) } |
注意這裡的修改:
- files只留下test檔案。因為webpack會自動把需要的其它檔案都打包進來,所以只需要留下入口檔案。
- preprocessors也修改為test檔案,並加入webpack域處理器
- 加入webpack配置選項。可以自己定製配置項,但是不需要entry和output。這裡加上babel-loader來編譯ES6程式碼
執行karma start
,成功了~
再看看Coverage,臥槽。。居然不是百分之百了。。。
原因很簡單,webpack會加入一些程式碼,影響了程式碼的Coverage。如果我們引入了一些其它的庫,比如jquery之類的,將原始碼和庫程式碼打包在一起後,覆蓋率會更難看。。這樣的Coverage就沒有了參考的價值。
還好有大神給我們提供瞭解決方案,需要安裝外掛
1 |
npm i --save-dev babel-plugin-istanbul |
修改webpack中babel-loader的配置
1 2 3 4 5 6 7 8 9 |
{ test: /\.js$/, loader: 'babel', exclude: /node_modules/, query: { presets: ['es2015'], plugins: ['istanbul'] } } |
因為這裡引入了istanbul外掛來檢測Coverage,所以要把preprocessors裡的coverage
去掉。
搞定以後,執行karma start
。噹噹噹當~一切OK啦,盡情編寫測試指令碼把~
最後附上示例專案地址:karma-example