基于 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 單測方案部署完畢。