在上一片文章中,我介绍了如何在 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 单测方案部署完毕。