基于 fis 的前端自動化單元測試方案
在上一片文章中,我介紹了如何在 fis 項目中使用 jasmine 進項單元測試,這個方案,可以解決 fis 中模塊的引用的問題, 整個單元測試可以 run 起來,但是,還是有很多不足:
- 人工成本較高,需要手動配置 runner 頁面,并在瀏覽器中查看結果。
- 難以統計單元測試的覆蓋率。
- 無法生成測試報告。
- 無法部署到 ci 系統中。
為了解決以上問題,故采用了全新方案,實現全自動單測。新方案主要包含以下改進:
- 采用 karmar 代替手動配置的 runner 頁面,測試 case 在 PhantomJS 跑。
- 采用 karmar-coverage 統計單測覆蓋率,并生成 統計結果頁面。
- 采用 karma-junit-report 生成測試報告。
karma.conf.js
我們知道,如果要引入 karma, 就需要通過 karma.conf.js 來配置相關的被測模塊和 case,fis 的代碼在編譯前和編譯后,會產生不同的 url,如何準確定位到單測的 case 和被測模塊文件呢?
值得慶幸的是,fis 的編譯會產出 map.json,所有資源的依賴關系都會記錄在其中。我們可以把所有的 js 文件和 map.json 都添加到 karma server 且不自動加載,然后通過 require.async 的方式異步加載所需資源。
module.exports = function (config) { config.set({ …… frameworks: ['jasmine'], reporters: ['progress', 'coverage', 'junit'], browsers: ['PhantomJS'], preprocessors: { '**/*.js': 'coverage'; }, coverageReporter: { type: 'html', dir: './coverage/' }, junitReporter: { outputDir: './report/', outputFile: 'report.xml' }, files: [ // 優先加載mod.js '**/*/common/mod*.js', // 當前模塊相關文件添加到Karma server上,設置included為false,不自動加載,通過modjs控制 {pattern: '**/*.js', included: false}, // 將map.json添加到 Karma server,后續讀取文件內容,用以確定資源依賴關系 {pattern: 'config/**/*-map.json', included: false}, // 加載測試入口文件 './test/' + project + '/' + namespace + '/test-main.js' ], …… }); };
test-main.js
測試入口文件,這里會讀取 map.json,重寫資源表中資源的路徑為 karma server 上的真實地址,同時重寫了 karma. start 方法,異步調用找出的 case 文件 (spec.js 結尾的文件 )。
(function () { var tests = []; if (window.XMLHttpRequest) // Firefox, Opera 8.0+, Safari,chrome,phantomjs xhr = new XMLHttpRequest(); else // IE xhr = new ActiveXObject("Microsoft.XMLHTTP"); // 遍歷在karma.conf.js的files中配置的相關文件,這些文件已經在karma server上 for (var _file in window.__karma__.files) { // 找到本模塊和被依賴模塊的map.json文件 if (window.__karma__.files.hasOwnProperty(_file) && _file.indexOf('map.json') > -1) { xhr.open('get', _file, false); xhr.send(); // 讀取map.json文件內容,定義為resourceMap var resourceMap = JSON.parse(xhr.responseText); for (var file in resourceMap.res) { // 找出本模塊所有單測文件 if (/\.spec\.js$/.test(file)) { console.log('add spec: ' + file); tests.push(file); } // 從karma server上保存的文件路徑中,獲取到resourceMap中所需文件的真實url for (var _file in window.__karma__.files) { if (window.__karma__.files.hasOwnProperty(_file) && _file.indexOf(resourceMap.res[file]['uri']) > -1) { resourceMap.res[file]['url'] = _file; } } } // 調用mod.js提供的require.resourceMap接口,將resourceMap打出來,以此確定資源的依賴關系和url require.resourceMap(resourceMap); } } // 由于使用自定義資源加載控制,因此需要重寫觸發 karma的方法 // 使用 jasmine 只需要在資源加載完畢之后觸發 start 方法即可 // 主動加載測試文件,后續mod.js根據resourceMap自動加載測試文件所需的被測文件以及被依賴的文件 var _fn = window.__karma__.start; window.__karma__.start = function () { require.async(tests, function () { _fn.call(); }); } })();
fis-conf.js
添加單測相關的輸出配置:
fis.config.set('roadmap.path', [{ reg: /^\/test\/(.*\.spec\.js)$/i, isMod: true, useHash: false, release: '/test/middlepage/yunying/${namespace}/$1' }, { reg: /^\/test\/(.*)/i, isMod: false, useHash: false, release: '/test/middlepage/yunying/${namespace}/$1' }, { reg: 'karma.conf.js', useHash: false, release: '/test/middlepage/yunying/${namespace}/$&' }].concat(fis.config.get('roadmap.path', [])));
目錄結構
整個 fis 項目的目錄類似如下:
編譯前
編譯后
運行測試
首先編譯指定 fis 模塊
fis release -r common -d output fis release module1 -d output
進入產出目錄,執行 karma start
cd output karma start test/module1/karma.conf.js
命令行可看到如下測試結果:
覆蓋率和統計報告
分別位于 output 目錄的 coverage 和 report 子目錄中(如 karma.conf.js 配置)。
部署CI
以 jenkins 為例:
-
在execute shell中填寫腳本:
cd /home/work/repos/fis2-karma
rm -rf ./output
fis release -r common -d ./output -mp
cd ./output
karma start test/common/karma.conf.js
-
設置 覆蓋率報告位置
- 設置測試結果報告位置
至此,整個 fis 單測方案部署完畢。