80931836 2019-06-20
单元测试的代码覆盖率统计,是衡量测试用例好坏的一个的方法,有的公司直接把代码测试覆盖率作为一个硬性要求。尤其在多人合作的情况下。很有可能在后期维护时候牵一发而动全身的代码修改中起到至关重要的检测。不过代码覆盖率也不是唯一标准,测试用例的好坏主要还是看能不能覆盖尽可能多的情况。
之前代码覆盖率在JS代码不需要编译的情况下。直接可以使用KARMA的karma-coverage这个工具就可以直接统计结果。不过由于我的项目用上了WEBPACK的打包和babel的ES6编译。所以单单使用karma-coverage统计的代码覆盖率统计的是,编译打包后的代码,这个覆盖率直接没有了参考价值。一般打包后代码的覆盖率只有可怜的10%-20%因为WEBPACK帮你加入了很多它的代码。而测试要做到这些代码的覆盖是完全没有意义的。所以就需要找一个可以查看编译前代码覆盖率的一个方法。
let navbar = angular.module('navbar', []); navbar.controller('navbarCtrl', ['$scope', function ($scope) { $scope.links = ['home', 'about']; }]); module.exports = navbar; //export default navbar;//ES6单元测试支持有问题。所以改用了module.exports = navbar;写法
import navbar from './navbar.ctrl.js'; describe('navbar', function () { let scope; beforeEach(angular.mock.module('navbar')); beforeEach(angular.mock.inject(function ($rootScope, $controller) { scope = $rootScope.$new(); $controller('navbarCtrl', {$scope: scope}); })); it('Controller测试', function () { expect(scope).to.have.property('links').with.length(2); }); });
然后带着上面的问题去GITHUB找有没有人解决过这样的问题,最后找到了isparta、isparta-instrumenter-loader、istanbul。
module.exports = function (config) { config.set({ // base path that will be used to resolve all patterns (eg. files, exclude) basePath: '', // frameworks to use // available frameworks: https://npmjs.org/browse/keyword/karma-adapter frameworks: ['mocha', 'chai'], // list of files / patterns to load in the browser files: ['app/**/*Spec.js'], // list of files to exclude exclude: [], // preprocess matching files before serving them to the browser // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor preprocessors: { 'app/**/*Spec.js': ['webpack', 'sourcemap'], 'app/**/*(!Spec).js': ['webpack', 'sourcemap', 'coverage'] }, // test results reporter to use // possible values: 'dots', 'progress' // available reporters: https://npmjs.org/browse/keyword/karma-reporter reporters: ['mocha', 'coverage'], coverageReporter: { reporters: [ {type: 'text-summary'}, {type: 'html', dir: 'coverage/'} ] }, // web server port port: 9876, // enable / disable colors in the output (reporters and logs) colors: true, // level of logging // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG logLevel: config.LOG_INFO, // enable / disable watching file and executing tests whenever any file changes autoWatch: false, // start these browsers // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher browsers: ['Chrome'], // Continuous Integration mode // if true, Karma captures browsers, runs the tests and exits singleRun: true, // Concurrency level // how many browser should be started simultaneous concurrency: Infinity, webpack: { devtool: 'inline-source-map', module: { preLoaders: [{ test: /\.js$/, exclude: [/node_modules/,/\.Spec.js$/], loader: 'isparta-instrumenter' }], loaders: [ {test: /\.js$/, exclude: [/node_modules/], loader: 'ng-annotate!babel'}, {test: /\.html/, loader: 'raw'}, {test: /\.styl$/, loader: 'style!css!stylus'}, {test: /\.css$/, loader: 'style!css'} ] } }, webpackServer: { noInfo: true // prevent console spamming when running in Karma! }, plugins: [ 'karma-chrome-launcher', 'karma-chai', 'karma-mocha', 'karma-webpack', 'karma-sourcemap-loader', 'karma-coverage', 'karma-mocha-reporter' ] }) };
以上完成了编译前代码覆盖率的统计。
files: ['app/**/*Spec.js'],
这个主要是导入那些是测试文件。
preprocessors: { 'app/**/*Spec.js': ['webpack', 'sourcemap'], 'app/**/*(!Spec).js': ['webpack', 'sourcemap', 'coverage'] },
这个是导入前的预处理,因为没有必要统计测试代码的覆盖率,所以测试代码只需要['webpack', 'sourcemap'],就可以了。而被测试代码需要统计覆盖率,所以需要['webpack', 'sourcemap', 'coverage']。
webpack: { devtool: 'inline-source-map', module: { preLoaders: [{ test: /\.js$/, exclude: [/node_modules/,/\.Spec.js$/], loader: 'isparta-instrumenter' }], loaders: [ {test: /\.js$/, exclude: [/node_modules/], loader: 'ng-annotate!babel'}, {test: /\.html/, loader: 'raw'}, {test: /\.styl$/, loader: 'style!css!stylus'}, {test: /\.css$/, loader: 'style!css'} ] } },
这个KARMA中的webpack配置是最关键的。需要在真是WEBPACK打包前用isparta-instrumenter先load一下,记录编译前文件。这里有一个坑。export default navbar;这句话是ES6支持的但是不知道为什么isparta-instrumenter-loader的时候就是编译有问题。所以只能改成module.exports = navbar;这样的写法。