zoukankan      html  css  js  c++  java
  • 学习Karma+Jasmine+istanbul+webpack自动化单元测试

    学习Karma+Jasmine+istanbul+webpack自动化单元测试

    1-1. 什么是karma?
      Karma 是一个基于Node.js的Javascript测试执行过程管理工具。该工具可用于测试所有主流web浏览器,也可集成到CI工具,也可以
    和其他代码编辑器一起使用,它可以监听文件的变化,然后自动执行。

    1-2. 什么是Jasmine?
    Jasmine也是一款javascript测试框架。Jasmine官网文档地址(https://jasmine.github.io/2.3/introduction.html)

    1-3. 什么是istanbul?
    istanbul 是一个单元测试代码覆盖率检查工具,它可以直观的告诉我们,单元测试对代码的控制程度。

    2. 安装Karma环境
    如下命令:

    npm install -g karma

    为了方便搭建karma环境,我们可以全局安装karma-cli来帮我们初始化测试环境。
    如下命令安装:

    npm install -g karma-cli

    我们在项目的根目录下也需要安装一下,如下命令:

    npm install karma --save-dev

    如上,安装完成以后,我们在项目的根目录下的命令行输入命令:karma start
    运行如下:

    karma start
    08 02 2018 21:38:49.566:WARN [karma]: No captured browser, open http://localhost:9876/
    08 02 2018 21:38:49.572:INFO [karma]: Front-end scripts not present. Compiling...
    08 02 2018 21:38:50.257:INFO [karma]: Karma v2.0.0 server started at http://0.0.0.0:9876/

    然后我们在浏览器输入 http://localhost:9876, 如下图所示:

    如果出现以上信息,表示karma已经安装成功了。

    3. karma的配置
    命令如下:

    karma init

    对上面命令的说明如下:
    1. 使用哪个测试框架,我们选择了jasmine
    2. 是否添加Require.js插件,我们选择no,不添加。
    3. 选择浏览器,我们选择了chrome。
    4. 测试文件路径设置,文件可以使用通配符匹配,比如*.js匹配指定目录下所有的js文件。
    5. 在测试文件路径下,需要被排除的文件。
    6. 是否允许karma监测文件,yes表示当测试文件变化时候,karma会自动测试。

    如上命令后,就会在项目的根目录下 生成 karma.conf.js 文件;
    下面对常用的 karma.conf.js 配置项进行解析说明如下:

    // Karma configuration
    // Generated on Thu Feb 08 2018 10:39:50 GMT+0800 (CST)
    
    module.exports = function(config) {
      config.set({
    
        // 将用于解析所有模式的基本路径
        basePath: '',
    
    
        // 选择测试框架,我们选择 'jasmine'
        // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
        frameworks: ['jasmine'],
    
    
        // 在浏览器中加载的匹配的文件列表。
        files: [
          /* 注意:是自己添加的 */
          'src/**/*.js',
          'test/**/*.js'
        ],
    
    
        // 要排除的文件列表
        exclude: [],// 在将其提供给浏览器之前,预处理匹配的文件,
        // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
        preprocessors: {
    
        },// 怎么显示测试结果 
        // 测试结果显示插件: https://npmjs.org/browse/keyword/karma-reporter
        reporters: ['progress'],
    
    
        // 服务器的端口号
        port: 9876,
    
        // 在输出中启用/禁用颜色(记录reporters和日志), 
        colors: true,
    
    
        // 显示日志记录的级别(默认就好)
        // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
        logLevel: config.LOG_INFO,
    
    
        // 当任何测试文件更改时候,启用/禁用监听文件并执行测试
        autoWatch: true,
    
    
        // start these browsers  启动的浏览器chrome
        // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
        browsers: ['Chrome'],
    
    
        // 持续集成模式,默认就好
        // if true, Karma captures browsers, runs the tests and exits
        singleRun: false,
    
        // 并发级别,可以同时启动多少个浏览器,默认无限大
        // how many browser should be started simultaneous
        concurrency: Infinity
      })
    }

    如上代码中的 config.set 中的 files 配置的  是我自己添加的;如下代码:

    files: [
      /* 注意:是自己添加的 */
      'src/**/*.js',
      'test/**/*.js'
    ]

    它的作用是:就是把需要测试的文件都require进来,然后一股脑的在browsers里面跑。

    4. 开启Karma
    命令如下: karma start
    手动打开chrome,输入localhost:9876 即可打开了。
    在控制台命令行中看到如下信息 说明运行成功了。

    ~/个人demo/vue1204/karma-demo on � Dev_20171115_wealth! 
    $ karma start
    08 02 2018 11:06:41.365:WARN [karma]: No captured browser, open http://localhost:9876/
    08 02 2018 11:06:41.379:INFO [karma]: Karma v2.0.0 server started at http://0.0.0.0:9876/
    08 02 2018 11:06:41.380:INFO [launcher]: Launching browser Chrome with unlimited concurrency
    08 02 2018 11:06:41.386:INFO [launcher]: Starting browser Chrome
    08 02 2018 11:06:42.457:INFO [Chrome 64.0.3282 (Mac OS X 10.11.6)]: Connected on socket JUZvceJFJhGgWFYJAAAA with id 7542403
    LOG: 111
    Chrome 64.0.3282 (Mac OS X 10.11.6): Executed 1 of 1 SUCCESS (0.011 secs / 0 secs)

    运行后会自动打开chrome浏览器,http://localhost:9876/?id=50037613 

    先来安装一下依赖的插件如下:

    1. 需要可以打开chrome浏览器的插件 npm install karma-chrome-launcher --save-dev
    2. 需要可以运行jasmine的插件 npm install karma-jasmine jasmine-core --save-dev
    3. 需要可以运行webpack的插件 npm install karma-webpack webpack --save-dev
    4. 需要可以显示的sourcemap的插件 npm install karma-sourcemap-loader --save-dev
    5. 需要可以显示测试代码覆盖率的插件 npm install karma-coverage-istanbul-reporter --save-dev
    6. 需要全局安装 jasmine-core 如命令:npm install -g jasmine-core
    如下一键安装命令:

    npm install --save-dev karma-chrome-launcher karma-jasmine karma-webpack karma-sourcemap-loader karma-coverage-istanbul-reporter

    也需要全局安装一下 jasmine-core, 如下代码:

    npm install -g jasmine-core

    我们可以写一个简单的测试用例;如下目录结构:

    karma-demo
        |---src
        |  --index.js
        |--- test
        | |-- index.test.js
        |
        |--- karma.conf.js

    src/index.js代码如下:

    function isNum(num) {
      if (typeof num === 'number') {
        return true;
      } else {
        return false;
      }
    }

    test/index.test.js代码如下:

    describe('测试用例编写', function() {
      it('isNum() should work fine', function() {
        console.log(111)
        expect(isNum(1)).toBe(true);
        expect(isNum('1')).toBe(false);
      });
    });

    如上代码我们可以看到 在 test/index.test.js 里面我们调用了 isNum方法,但是并没有使用require引用进来而可以使用,那是因为
    我们的karma.conf.js里面的配置文件 files里面设置了,因此没有使用require就可以使用了。

    files: [
    /* 注意:是自己添加的 */
    'src/**/*.js',
    'test/**/*.js'
    ]

    它的作用是:就是把需要测试的文件都require进来,然后一股脑的在browsers里面跑。

    5. Coverage
    如何测量测试脚本的质量呢?其中有一个参考指标就是代码覆盖率。
    5-1:什么是代码覆盖率?
    代码覆盖率是在测试中运行到的代码占所有代码的比率。因此接下来我们在Karma环境中添加Coverage。
    在项目的根目录下,运行如下命令进行安装

    npm install --save-dev karma-coverage

    然后需要在配置文件 karma.conf.js 代码配置如下:

    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: ['jasmine'],
    
    
        // list of files / patterns to load in the browser
        files: [
          /* 注意:是自己添加的 */
          'src/**/*.js',
          'test/**/*.js'
        ],
    
    
        // list of files / patterns to exclude
        exclude: [],
    
    
        // preprocess matching files before serving them to the browser
        // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
        /* 覆盖源文件 不包括测试库文件*/
        preprocessors: {
          'src/**/*.js': ['coverage']
        },
        
    
        // test results reporter to use
        // possible values: 'dots', 'progress'
        // available reporters: https://npmjs.org/browse/keyword/karma-reporter
        reporters: ['progress', 'coverage'],
        
        /* 新增的配置项 */
        coverageReporter: {
          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: true,
    
    
        // 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: false,
    
        // Concurrency level
        // how many browser should be started simultaneous
        concurrency: Infinity
      })
    }

    具体的配置可以参考  https://www.npmjs.com/package/karma-coverage

    再运行下 karma start后,会在根目录下生产 coverage目录,里面有index.html作为本次的测试报告,我们打开看下,如下:

    如上代码的覆盖率是对源文件需要被测试的覆盖率是100%;
    要生成代码覆盖率,可以看这篇文章(http://karma-runner.github.io/0.8/config/coverage.html
    想要生成覆盖率,需要在配置项配置如下三个选项:
    1. preprocessors coverage (必须配置的)
    2. reporters coverage (必须配置的)
    3. reporter options (可选的)

    1. Preprocessors(配置预处理器)
    preprocessors 的含义是:是那些测试文件需要被覆盖,比如,如果所有代码都在src/下的文件 您需要添加到您的配置文件,如上
    配置代码:

    preprocessors: {
      'src/**/*.js': ['coverage']
    }

    注意: 不要包含你所依赖的库,测试文件等等,下面就是一个错误的配置信息。

    files = [
      JASMINE,
      JASMINE_ADAPTER,
      'lib/*.js',
      'test/*.js'
    ];
    preprocessors = {
      '**/*.js': 'coverage'
    };

    2. Reporters(配置报告)
    在配置文件中包含下面的信息来激活覆盖率报告器。
    如上配置代码:

    reporters: ['progress', 'coverage'],

    这样将会对每个浏览器创建一个覆盖率报告,另外,它还会创建一个 Json 文件,其中包含输出的中间数据。

    3. Reporter Options(配置报告选项)
    默认的报告格式如下:

    coverageReporter: {
      type: 'html',
      dir: 'coverage/'
    },

    type 是一个字符串值,取值可以是:
    html (default)
    lcov (lcov and html)
    lcovonly
    text
    text-summary
    cobertura (xml format supported by Jenkins)
    dir 则用来配置报告的输出目录。
    如果类型是 text 或者 text-summary,你可以配置 file 参数来指定保存的文件名。

    coverageReporter = {
      type : 'text',
      dir : 'coverage/',
      file : 'coverage.txt'
    }

    如果没有文件名,就会输出到控制台。

    6. webpack和Babel集成Karma环境中。
    在项目中,会使用到webpack和es6,因此需要集成到karma环境中。
    安装karma-webpack

    npm install --save-dev karma-webpack webpack

    1.安装babel核心文件 npm install babel-core --save-dev
    2. webpack的Loader处理器 npm install babel-loader --save-dev
    3. babel的istanbul覆盖率插件 npm install babel-plugin-istanbul --save-dev
    4. babel转换到哪个版本这里是ES2015 npm install babel-preset-es2015 --save-dev

    一键安装命令如下:

    npm install --save-dev babel-loader babel-core babel-preset-es2015 babel-plugin-istanbul

    然后 src/index.js 代码变成如下:

    function isNum(num) {
      if (typeof num === 'number') {
        return true;
      } else {
        return false;
      }
    }
    
    module.exports = isNum;

    test/index.test.js 变成如下:

    const isNum = require('../src/index');
    
    describe('测试webpack+babel集成到Karma中', () => {
      it('isNum() should work fine.', () => {
        expect(isNum(1)).toBe(true);
        expect(isNum('1')).toBe(false);
      })
    });

    接下来修改配置文件karma.conf.js 如下配置代码:

    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: ['jasmine'],
    
    
        // list of files / patterns to load in the browser
        files: [
          /* 注意:是自己添加的 */
          'test/**/*.js'
        ],
    
    
        // list of files / patterns to exclude
        exclude: [],
    
    
        // preprocess matching files before serving them to the browser
        // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
        preprocessors: {
          'test/**/*.js': ['webpack', 'coverage']
        },
    
    
        // test results reporter to use
        // possible values: 'dots', 'progress'
        // available reporters: https://npmjs.org/browse/keyword/karma-reporter
        reporters: ['progress', 'coverage'],
    
        /* 新增的配置项 */
        coverageReporter: {
          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: true,
    
    
        // 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: false,
    
        // Concurrency level
        // how many browser should be started simultaneous
        concurrency: Infinity,
        webpack: {
          module: {
            loaders: [{
              test: /.js$/,
              loader: 'babel-loader',
              exclude: /node_modules/,
              query: {
                presets: ['es2015']
              }
            }]
          }
        }
      })
    }

    如上代码修改的地方:
    1. files只留下test文件。因为webpack会自动把需要的其它文件都打包进来,所以只需要留下入口文件。
    2. preprocessors也修改为test文件,并加入webpack域处理器。
    3. 加入webpack配置选项。可以自己定制配置项,但是不需要entry和output。这里加上babel-loader来编译ES6代码

    命令行运行karma start,成功了~

    但是我们再来看看 coverage/xx/index.html

    如上图测试覆盖率 不是100%;
    原因是webpack会加入一些代码,影响了代码的Coverage。如果我们引入了一些其它的库,比如jquery之类的,将源代码和库代码打包在一起后,覆盖率会更难看。
    因此我们需要安装如下插件来解决上面的问题。
    istanbul的介绍:
    istanbul是一个单元测试代码覆盖率检查工具,可以很直观地告诉我们,单元测试对代码的控制程度。

    1. webpack的Loader处理器 npm install istanbul-instrumenter-loader --save-dev
    2. 测试覆盖率显示插件 npm install karma-coverage-istanbul-reporter --save-dev

    然后我们去修改 karma.conf.js

    webpack: {
      module: {
        rules: [
          {
            test: /.js$/,
            use: {
              loader: 'babel-loader',
              options: {
                presets: ['es2015'],
                plugins: ['istanbul']
              } 
            },
            exclude: /node_modules/
          }
        ]
      }
    }

    先给babel加上插件 plugins: ['istanbul'];
    再写上 istanbul-instrumenter-loader 的配置,所以整个配置的代码变成如下:

    然后把 karma.conf.js 配置改成如下:

    webpack: {
      module: {
        rules: [
          {
            test: /.js$/,
            use: {
              loader: 'istanbul-instrumenter-loader',
              options: { esModules: true }
            },
            enforce: 'pre',
            exclude: /node_modules/
          },
          {
            test: /.js$/,
            use: {
              loader: 'babel-loader',
              options: {
                presets: ['es2015'],
                plugins: ['istanbul']
              } 
            },
            exclude: /node_modules/
          }
        ]
      }
    }

    具体可以看 https://doc.webpack-china.org/loaders/istanbul-instrumenter-loader 的API。
    因此所有的karma.conf.js 的配置代码如下:

    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: ['jasmine'],
    
    
        // list of files / patterns to load in the browser
        files: [
          /* 注意:是自己添加的 */
          'test/**/*.js'
        ],
    
    
        // list of files / patterns to exclude
        exclude: [],
    
    
        // preprocess matching files before serving them to the browser
        // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
        preprocessors: {
          'test/**/*.js': ['webpack']
        },
    
    
        // test results reporter to use
        // possible values: 'dots', 'progress'
        // available reporters: https://npmjs.org/browse/keyword/karma-reporter
        reporters: ['progress', 'coverage'],
    
        /* 新增的配置项 */
        coverageReporter: {
          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: true,
    
    
        // 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: false,
    
        // Concurrency level
        // how many browser should be started simultaneous
        concurrency: Infinity,
        webpack: {
          module: {
            rules: [
              {
                test: /.js$/,
                use: {
                  loader: 'istanbul-instrumenter-loader',
                  options: { esModules: true }
                },
                enforce: 'pre',
                exclude: /node_modules/
              },
              {
                test: /.js$/,
                use: {
                  loader: 'babel-loader',
                  options: {
                    presets: ['es2015'],
                    plugins: ['istanbul']
                  } 
                },
                exclude: /node_modules/
              }
            ]
          }
        }
      })
    }

    再运行  karma start 即可。

    7. 怎么测试覆盖率
    覆盖率它有四个测量维度。
    1. 行覆盖率(line coverage): 是否每一行都执行了?
    2. 函数覆盖率(function coverage): 是否每个函数都调用了?
    3. 分支覆盖率 (branch coverage): 是否每个if代码都执行了?
    4. 语句覆盖率(statement coverage): 是否每个语句都执行了?

    karma-demo
        |---src
        |  |--index.js
        |  |--- add.js
        |--- test
        | |-- index.test.js
        | |-- add.test.js
        |
        |--- karma.conf.js

    如上demo,我们在项目中的src路径下新增add.js代码如下:

    function add (num1, num2) {
      return num1 + num2;
    }
    
    module.exports = add;

    在test/add.test.js代码如下:

    const add = require('../src/add');
    
    describe('加法运算', () => {
      it('测试简单的两个数相加', () => {
        expect(add(1, 1)).toBe(2);
      })
    });

    然后我们继续运行 karma start 后,会生成 coverage / xx/ index.html 运行结果如下:

    现在我们将add.js代码变复杂点,如果不写num2, 就默认为0,如下代码:

    function add (num1, num2) {
      if (num2 === undefined) {
        num2 = 0;
      }
      return num1 + num2;
    }
    
    module.exports = add;

    test/add.test.js 代码如下:

    const add = require('../src/add');
    
    describe('第二个测试套件', function() {
        it('第一个测试用例: 1+1 === 2', function() {
            expect(add(1)).toBe(2);
        });
    });

    我们继续karma start后,再打开 coverage下的index.html文件变为如下:

    测试结果分析:
    1个分支覆盖率(branch coverage)没有覆盖到,1个函数和1个语句被覆盖到,4行行覆盖率全部被覆盖。

    我们再继续对add.js代码进行改造。

    function add (num1, num2) {
      if (num1 === undefined) {
        num1 = 0;
      }
      if (num2 === undefined) {
        num2 = 0;
      }
      return num1 + num2;
    }
    
    module.exports = add;

    add.test.js 代码测试如下:

    const add = require('../src/add');
    describe('第二个测试套件', function() {
      it('第1个测试用例: 1+1 === 2', function() {
        expect(add(1, 1)).toBe(2);
      });
      it('第2个测试用例: 1+1 === 2', function() {
        expect(add()).toBe(0);
      });
      it('第3个测试用例: 1+1 === 2', function() {
        expect(add(1)).toBe(1);
      });
      it('第4个测试用例: 1+1 === 2', function() {
        expect(add(2, 1)).toBe(3);
      });
    });

    如上测试代码就全部覆盖到了。

    查看github上的demo

  • 相关阅读:
    Elementary Methods in Number Theory Exercise 1.2.25
    Elementary Methods in Number Theory Exercise 1.2.14
    图解欧几里德算法
    图解欧几里德算法
    Elementary Methods in Number Theory Exercise 1.2.14
    Android中的长度单位详解(dp、sp、px、in、pt、mm)
    分享下多年积累的对JAVA程序员成长之路的总结
    android异常之都是deamon惹的祸The connection to adb is down, and a severe error has occured.
    TomatoCartv1.1.8.2部署时报错
    JavaScript浏览器对象之二Document对象
  • 原文地址:https://www.cnblogs.com/tugenhua0707/p/8433847.html
Copyright © 2011-2022 走看看