频道栏目
首页 > 程序开发 > web前端 > JavaScript > 正文
[Node.js] Express的测试覆盖率
2014-12-04 08:30:46           
收藏   我要投稿
引子

有群友问到Express怎么做 单元测试/覆盖率测试,这是上篇所遗漏的,特此补上

 

Express Web测试

做 Express Web 测试首先要面对的问题是在哪端进行测试:

 

客户端的请求响应测试是黑盒,需要预启动站点,且无法附加覆盖率测试

服务端的单元测试需要 Mock ,可附加覆盖率测试

我们需要对Express的路由做覆盖率测试,显然,我们会选择在服务端进行测试。这意味着:每个case需要访问的express application 不是这样预先启动的:

 

var express = require('express');

var app = express();

//some router code...

app.listen(3000);

我们需要一个工具能创建启动express application,并 Mock 对它的请求,只有这样,测试框架才能检测到路由方法内部代码执行的路径和覆盖率。

 

这里,我们引入supertest 做为 mock 工具。

 

SuperTest

SuperTest 是TJ大神的又一款作品:基于SuperAgent ,提供对HTTP测试的高度抽象。所谓高度抽象的意思是:能嵌入各类测试框架,提供语义良好的断言。

 

来看段 SuperTest结合 Mocha的代码:

 

复制代码

var app = require('../app');

var request = require('supertest');

 

describe('router testing', function () {

    it('site root response', function (done) {

        request(app)

            .get('/')

            .expect('Content-Type', 'text/html; charset=utf-8')

            .expect(200)

            .end(function(err, res){

                if (err) throw err;

                done();

            });

    });

复制代码

简单易懂,重点是它驱动了express。

 

测试覆盖率

代码覆盖(Code coverage)是软件测试中的一种度量,描述程式中源代码被测试的比例和程度,所得比例称为代码覆盖率。

 

以下是几个覆盖率指标:

 

函数覆盖率(Function coverage):调用到程式中的每一个Function吗?

行覆盖率(Line coverage):执行到程序中的每一行了吗?

语句覆盖率(Statement coverage):若用控制流图表示程序,执行到控制流图中的每一个节点了吗?

分支覆盖率(Branches coverage):若用控制流图表示程式,执行到控制流图中的每一条边吗?例如控制结构中所有IF指令都有执行到逻辑运算式成立及不成立的情形吗?

条件覆盖率(Condition coverage):也称为谓词覆盖(predicate coverage),每一个逻辑运算式中的每一个条件(无法再分解的逻辑运算式)是否都有执行到成立及不成立的情形吗?

对指标的偏好可说是见仁见智,比如大名鼎鼎的 coveralls.io 就以行覆盖率(Line coverage) 作为给项目颁发badge的首选指标。

 

我们需要的,是一个能根据测试用例得出覆盖率指标的工具:

 

Istanbul

istanbul 就是这样一个工具,能产生 Statements/Lines/Functions/Branches 等指标报表,并以各种格式导出。

 

值得称道的是,istanbul 能和 Mocha 很好的集成,如:把测试用例统一放置在 /test下,要对它们进行测试并生成覆盖率报表,可以在 package.json 中添加这样的配置:

 

"scripts": {

    "test": "mocha --recursive --timeout 500000 test/ --bail",

    "test-cov": "node node_modules/istanbul-harmony/lib/cli.js cover ./node_modules/mocha/bin/_mocha  -- --timeout 500000 --recursive test/ --bail"

}

只需要进行测试时,在项目目录下使用命令:

 

1

npm test

需要进行测试并追加覆盖率报表时,在项目目录下使用命令:

 

1

npm run-script test-cov

在测试部分完成后,会得到如下报表信息(在项目 /coverage 目录下,会生成lcov.info 等覆盖率数据文件:

 

istanbul_coverage

 

实例

mock 工具有了, 测试框架和覆盖率工具也有了,就差实战了。下面举个粟子看看怎么做 Express 的覆盖率测试:

 

全局安装 mocha ,istanbul 及 express

npm install -g mocha

npm install -g istanbul

npm install -g express

生成一个express 站点:

express -e express-coverage

修改package.json如下,并使用npm install 安装需要的包:

复制代码

{

  "name": "express-coverage",

  "version": "0.0.1",

  "scripts": {

    "test": "mocha test/ --bail",

    "test-cov": "node node_modules/istanbul-harmony/lib/cli.js cover ./node_modules/mocha/bin/_mocha  -- test/"

  },

  "dependencies": {

    "express": "~4.9.0",

    "body-parser": "~1.8.1",

    "cookie-parser": "~1.3.3",

    "morgan": "~1.3.0",

    "serve-favicon": "~2.1.3",

    "debug": "~2.0.0",

    "ejs": "~0.8.5",

    "istanbul-harmony": "*",

    "should": "*",

    "mocha": "*",

    "mocha-lcov-reporter": "*",

    "supertest" : "*"

  }

}

复制代码

把自带的routes/index.js,、bin/www 删除;改写routes/users.js:

复制代码

var express = require('express');

var router = express.Router();

router.get('/', function (req, res) {

    var msg = 'no user';

    res.send(msg);

});

router.get('/:id', function (req, res) {

    var msg = 'user: ' + req.params.id;

    res.send(msg);

});

module.exports = router;

复制代码

在项目下新建一个test目录,放置一个 router.js,并编写用例:

复制代码

var should = require('should');

var app = require('../app');

var request = require('supertest');

describe('router testing', function () {

    it('users have not id response', function (done) {

        request(app)

            .get('/users')

            .expect('Content-Type', 'text/html; charset=utf-8')

            .expect(200)

            .end(function(err, res){

                if (err) throw err;

                should.exist(res.text);

                done();

            });

    });

 

    it('users have id response', function (done) {

        request(app)

            .get('/users/1/')

            .expect('Content-Type', 'text/html; charset=utf-8')

            .expect(200)

            .end(function(err, res){

                if (err) throw err;

                should.exists(res.text);

                done();

            });

    });

});

复制代码

输入命令npm run-script test-cov 得到覆盖率报表: 

testing_coverage_first

指标有点低是不是,因为app里有分支和代码是用例没跑到的: 404和500处理代码(这些是express-generator的生成代码:

复制代码

app.use(function(req, res, next) {

    var err = new Error('Not Found');

    err.status = 404;

    next(err);

});

app.use(function(err, req, res, next) {

    res.status(err.status || 500);

    res.render('error', {

        message: err.message,

        error: {}

    });

});

复制代码

在 router.js 原有场景中,添加一个用例,加上对404代码行的触发:

复制代码

it('404 response', function (done) {

    request(app)

        .get('/non/')

        .expect(404)

        .end(function(err, res){

            if (err) throw err;

            done();

        });

});

点击复制链接 与好友分享!回本站首页
相关TAG标签 覆盖率
上一篇:ATL - JavaScript混合编程
下一篇:UIWebView和网页的交互(OC中调执行JS)
相关文章
图文推荐
点击排行

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站