• mocha、chai、sinon和istanbul实现100%单元测试覆盖率


    敏捷软件开发中,最重要实践的就是测试驱动开发,在单元测试层面,我们试着实现一个重要的指标就是测试覆盖率。测试覆盖率衡量我们的代码是否已经全部被测试到了。

    但是指标本身不是目的,借助测试覆盖率检查,我们希望发现那些未被测试覆盖的代码,从而去思考如何测试那些代码的逻辑,进而更好的设计重构代码,让代码有更高的质量[1]

    谈到测试,正好最近在看《数学之美》,书中谈到的关于信息的一段话。我们要把代码的行为从不确定性,变成确定性,也是一样。从黑盒变成白盒,没有什么神奇的力量,唯有提供足够的信息,而测试中的断言就是信息,测试覆盖率也是信息,测试覆盖率可以认为是一种间接的信息,可以消除一部分不确定性,而充分的断言,则提供了更直接的信息。加上测试覆盖率检查,就能够提供足够的信息,来断言代码的行为是否符合期望。

    测试的相关技术

    IstanbulJavaScript程序的代码覆盖率工具,以土耳其最大城市伊斯坦布尔命名。Istanbul会对代码进行转换,生成语法树,然后在相应位置注入统计代码,执行之后根据注入的全局变量的值,统计代码执行的次数;在对代码的转换完成之后,Istanbul会调用test runner,例如mocha,执行转换之后的代码的测试,生成测试报告。

    Mocha是一种测试框架,也就是运行测试的工具,类似Jasmine、Karma和Ava。跟JUnit的注解一样,mocha作为执行器,用descibeit方法,来定义test suit,为不同的测试分组。mocha本身并不提供assert断言,所以要提供更加有表现力的断言,可以搭配chai使用,当然也可以使用nodejs提供的assert模块

    在我们的代码中,总会有一些复杂的逻辑或者依赖io、网络的异步代码,用直接的方法难以测试,这时可以通过sinon简化复杂代码的测试。Sinon通过创建Test Double也就是测试替身,将我们代码中依赖的一些函数或者类,替换成测试替身,而我们可以对测试替身的行为进行设置,模拟我们的代码需要的结果,从而让难以测试的代码逻辑被执行。

    为nodejs项目配置测试环境

    1 安装相应的依赖包

    mocha和istanbul可以全局安装,也可以只在当前项目安装。

    npm install --save-dev mocha chai sinon istanbul

    安装完成之后,在package.json文件的scripts下,添加执行测试和测试覆盖率检查的命令

    {
      ...
      "scripts":{
        "coverage": "istanbul cover _mocha -- -R spec --timeout 5000 --recursive",
        "coverage:check": "istanbul check-coverage",
      }
      ...
    }

    运行npm run coveragenpm run coverage:check,就可以生成测试报告,前者生成测试报告,后者则是检查测试覆盖率是否达到要求。

    2 配置Istanbul

    istanbul相关的执行参数,可以在命令行下执行时传递参数来制定,也可以在yaml格式的.istanbul.yml文件中配置。简单贴出一些重要的配置项

    instrumentation:
      root: .   # 执行的根目录
      extensions:
        - .js   # 检查覆盖率的文件扩张名
      excludes: ['**/benchmark/**']
    
      ... ...
    
    reporting:
      print: summary
      reports: [lcov, text, html, text-summary] # 生成报告的格式
      dir: ./coverage   # 生成报告保存的目录
      watermarks:       # 在不同覆盖率下会显示使用不同颜色
        statements: [80, 95]
        ... ...
    check:
      global:
        statements: 100
        branches: 100
        lines: 100
        functions: 100

    最后的check是项目要通过覆盖率检查需要达到的测试覆盖率,测试覆盖率包括四个维度,分别是语句覆盖率、分支覆盖率、行覆盖率和函数覆盖率。如果达不到设定的指标,在执行的时候会报错,项目的测试就无法通过自动化的持续集成。

    编写测试代码

    敏捷软件开发中的测试驱动开发,意在通过先写测试,根据调用者的契约,设计如何实现代码,从而写出更加容易测试的代码,提高代码的质量。也是我们练习测试的应该考虑的方向。

    1 一段简单的mocha测试代码

    利用chai提供的expect断言,我们可以用BDD的方式,写出更加符合代码预期行为的测试用例。

    var chai = require('chai')
    
    chai.should()
    var expect = chai.expect
    var assert = chai.assert
    
    describe('basic test', function () {
      describe('simple', function () {
        it('data check', function () {
          var data = { name: "test" }
    
          assert.isNotNull(data, 'data should not be null')
          expect(data).to.be.an('object')
          expect(data).to.have.all.keys(['name'])
          expect(data).to.deep.include({name: 'test'});
        });
      });
    });

    2 用Sinon模拟文件读写

    ... 同上 ...
    var sinon = require('sinon')
    var fs = require('fs')
    
    describe('sinon', function () {
      it("should mock readFile", function(done){
        sinon.stub(fs, 'readFile').callsFake(function (path, callback) { callback(new Error('read error')) })
    
        fs.readFile("any file path", function(err,data){
          assert.isNotNull(err)
          done()
        })
        assert(fs.readFile.calledOnce)
      });
    });

    在mocha测试框架中,如果我们调用的是异步的代码,那么需要显示的调用it回调函数的done方法,告诉mocha异步调用什么时候结束。否则的话,测试会挂起,直到设置的超时时间结束。

    Sinon将测试替身分为spy、stub和mock,其中:

    • Spy, 可以提供函数调用的信息,但不会改变函数的行为
    • Stub, 提供函数的调用信息,并且可以像示例代码中一样,让被stubbed的函数返回任何我们需要的行为。
    • Mock, 通过组合spies和stubs,使替换一个完整对象更容易。

    本文的讨论篇幅有限,暂时不详细介绍各种sinon的使用方法,以后再通过其他文章专门介绍。

    持续集成

    完成所有代码之后,我们可以将代码发布到github,然后使用持续集成工具travis检查代码,将生成的测试报告上传到coverall上,这样就可以在项目中显示项目状态和测试覆盖率的badges。

    具体使用方法,可以参看官方网站,使用coveralls需要在项目中安装依赖包npm i -D coveralls。并且添加package.json执行脚本istanbul cover ./node_modules/mocha/bin/_mocha --report lcovonly -- -R spec && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js

    通常的nodejs项目.travis.yml配置如下:

    language: node_js
    node_js:
      - "7.6.0"
    install:
      - npm install
    script:
      - npm test
    after_script:
      - npm run coverall

    原文地址:http://www.51test.space/archives/2543

  • 相关阅读:
    【百度地图API】如何快速创建带有标注的地图?——快速创建地图工具+如何标注商家
    【百度地图API】百度做了一个艰难的决定——取消密钥机制!!
    【设计师工具】3个好用的在线配色工具
    【百度地图API】建立全国银行位置查询系统(二)——怎样为地图添加控件
    【百度地图API】如何在地图上添加标注?——另有:坐标拾取工具+打车费用接口介绍
    【百度地图API】多家地图API文件大小对比
    “街坊”房产数字平台,昔日的思想,曾经的努力
    软件工程之感想
    .net执行性能,Winform性能优化?如何提高.net程序性能
    个人之思考整理
  • 原文地址:https://www.cnblogs.com/51test/p/7146503.html
Copyright © 2020-2023  润新知