原文地址:http://www.moye.me/2014/12/03/express_coverage/
有群友问到Express怎么做 单元测试/覆盖率测试,这是上篇所遗漏的,特此补上
做 Express Web 测试首先要面对的问题是在哪端进行测试:
我们需要对Express的路由做覆盖率测试,显然,我们会选择在服务端进行测试。这意味着:每个case需要访问的express application 不是这样预先启动的:
var express = require('express'); var app = express(); //some router code... app.listen(3000);
我们需要一个工具能创建启动express application,并 Mock 对它的请求,只有这样,测试框架才能检测到路由方法内部代码执行的路径和覆盖率。
这里,我们引入supertest 做为 mock 工具。
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)是软件测试中的一种度量,描述程式中源代码被测试的比例和程度,所得比例称为代码覆盖率。
以下是几个覆盖率指标:
对指标的偏好可说是见仁见智,比如大名鼎鼎的 coveralls.io 就以行覆盖率(Line coverage) 作为给项目颁发badge的首选指标。
我们需要的,是一个能根据测试用例得出覆盖率指标的工具:
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" }
只需要进行测试时,在项目目录下使用命令:
npm test
需要进行测试并追加覆盖率报表时,在项目目录下使用命令:
npm run-script test-cov
在测试部分完成后,会得到如下报表信息(在项目 /coverage 目录下,会生成lcov.info 等覆盖率数据文件:
mock 工具有了, 测试框架和覆盖率工具也有了,就差实战了。下面举个粟子看看怎么做 Express 的覆盖率测试:
npm install -g mocha
npm install -g istanbul
npm install -g express
express -e express-coverage
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" : "*" } }
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;
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
得到覆盖率报表: 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: {} }); });
it('404 response', function (done) { request(app) .get('/non/') .expect(404) .end(function(err, res){ if (err) throw err; done(); }); });
npm run-script test-cov
查看覆盖率报表,我们能看到进步 :) 找到合适的 Mock工具和测试框架并进行整合,Web测试及覆盖率报表获取的思路大抵如此。关于测试框架的各种参数组合和花样玩法,还有很多有意思的功能(比如和 Travis-CI、Coveralls.io 等公共服务集成,在仓库上展示项目状态徽章),本文不再赘述,有兴趣的可加node学习交流群一起探讨。
更多文章请移步我的blog新地址: http://www.moye.me/