JavaScript代码覆盖率工具 Istanbul入门

@kvkens 2016-08-07 12:58:19发表于 iuap-design/blog

代码覆盖率其实我觉得一直离我很远,但是我现在觉得维护的库代码是否所有的都执行过了,早的时候我在cnodejs社区就看到唐少写的跑覆盖率测试,看来这个东西蛮必要的,所以就把学习的经历分享下…… :)

引用阮一峰的一段博客:
"代码覆盖率"(code coverage)。它有四个测量维度分别是:

  • 行覆盖率(line coverage):是否每一行都执行了?
  • 函数覆盖率(function coverage):是否每个函数都调用了?
  • 分支覆盖率(branch coverage):是否每个if代码块都执行了?
  • 语句覆盖率(statement coverage):是否每个语句都执行了?
Istanbul 是 JavaScript 程序的代码覆盖率工具,介绍下它的用法吧。

1、安装

Istanbul 是npm的一个模块,命令如下:

npm install -g istanbul

安装完成后,我们来看看怎么使用

2、覆盖率测试

新建脚本文件test.js

var x = 5;
var y = 7;
if ((x + y) > 12) {
  console.log('大于12');
}

然后使用 istanbul cover 命令,就能得到覆盖率。

执行istanbul cover test.js

D:\Code\FEStudy\istanbul>istanbul cover test.js
=============================================================================
Writing coverage object [D:\Code\FEStudy\istanbul\coverage\coverage.json]
Writing coverage reports at [D:\Code\FEStudy\istanbul\coverage]
=============================================================================

=============================== Coverage summary ==============================

Statements   : 75% ( 3/4 )
Branches     : 50% ( 1/2 )
Functions    : 100% ( 0/0 )
Lines        : 75% ( 3/4 )
===============================================================================

看到结果是酱紫的……

test.js 有4个语句(statement),执行了3个;有2个分支(branch),执行了1个;有0个函数,调用了0个;有4行代码,执行了3行。

同时还在项目根目录生成一个文件夹coverage,打开coverage/lcov-report/index.html

其中的 coverage.json 文件包含覆盖率的原始数据,coverage/lcov-report 是可以在浏览器打开的覆盖率报告,其中有详细信息,到底哪些代码没有覆盖到。

3、覆盖率门槛

完美的覆盖率当然是 100%,但是现实中很难达到。需要有一个门槛,衡量覆盖率是否达标。

istanbul check-coverage 命令用来设置门槛,同时检查当前代码是否达标。

istanbul check-coverage --statement 90

ERROR: Coverage for statements (75%) does not meet global threshold (90%)

上面命令设置语句覆盖率的门槛是 90% ,结果就报错了,因为实际覆盖率只有75%。
除了百分比门槛,我们还可以设置绝对值门槛,比如只允许有一个语句没有被覆盖到。
istanbul check-coverage --statement -1

上面命令使用负数,表示绝对值门槛。这样一来,上面的例子就通过了覆盖率测试,不会再报错了。
百分比门槛和绝对值门槛,可以结合使用。

istanbul check-coverage --statement -5 --branch -3 --function 100

上面命令设置了3个覆盖率门槛:5个语句、3个 if 代码块、100%的函数。注意,这三个门槛是"与"(and)的关系,只要有一个没有达标,就会报错。

4、与测试框架的结合

给大家介绍下与mocha测试框架一起使用

sqrt.js 是一个计算平方根的脚本。

var My = {
  sqrt: function(x) {
    if (x < 0) throw new Error("负值没有平方根");
      return Math.exp(Math.log(x)/2);
    }
};

module.exports = My;

它的测试脚本 test.sqrt.js 放在 test 子目录。

var chai = require('chai');
var expect = chai.expect;
var My = require('../sqrt.js');

describe("sqrt", function() {

  it("4的平方根应该等于2", function() {
    expect(My.sqrt(4)).to.equal(2);
  });

  it("参数为负值时应该报错", function() {
    expect(function(){ My.sqrt(-1); }).to.throw("负值没有平方根");
  });

});

然后,执行下面的命令得到代码覆盖率。

 istanbul cover _mocha
// or
 istanbul cover _mocha test/test.sqrt.js

  sqrt
    ✓ 4的平方根应该等于2 
    ✓ 参数为负值时应该报错 

  2 passing (7ms)

===== Coverage summary =====
Statements   : 100% ( 5/5 )
Branches     : 100% ( 2/2 )
Functions    : 100% ( 1/1 )
Lines        : 100% ( 4/4 )
=============================

上面命令中,istanbul cover 命令后面跟的是 _mocha 命令,前面的下划线是不能省略的。
因为,mocha 和 _mocha 是两个不同的命令,前者会新建一个进程执行测试,而后者是在当前进程(即 istanbul 所在的进程)执行测试,只有这样, istanbul 才会捕捉到覆盖率数据。其他测试框架也是如此,必须在同一个进程执行测试。

(完)

参考文献:Cnodejs.org & 阮一峰博客