supertest是一个HTTP 服务器测试模块,它让HTTP断言变得非常简单。它可以直接引入Express项目的app.js文件进行测试,也可以通过一个测试网址创建测试用例。你可以很容易的将它集成到Mocha测试框架中。
1. 模块介绍与安装
supertest为测试HTTP的提供了一个高层次的抽象;当然你也可以使用其API还,以super-agent(超级代理)的模式进行较低层的测试。
模块安装
我们可以使用npm命令安装这上模块,并通过--save-dev参数将依赖关系保持到package.json文件的devDependencies节点中:
npm install supertest --save-dev
安装后,就可以在项目中使用require()方法引用这个模块:
var request = require('supertest');
2. 使用示例
你可以传入一个http.Server对象或Function到request()方法中,如果传入服务器对象还没有创建连接监听,SuperTest会为其创建一个临时的端口绑定。
SuperTest可以运行在任意测试框架中,如果不需要使用任何测试框架,可以像下面这样使用:
var request = require('supertest');
var express = require('express');
var app = express();
app.get('/user', function(req, res){
res.status(200).json({ name: 'tobi' });
});
request(app)
.get('/user')
.expect('Content-Type', /json/)
.expect('Content-Length', '15')
.expect(200)
.end(function(err, res){
if (err) throw err;
});
在Mocha框架中,你可以任意.expect()目标方法中传入done参数,以在指定处理完成后进行回调:
describe('GET /user', function(){
it('respond with json', function(done){
request(app)
.get('/user')
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect(200, done);
})
})
在以上示例中,我们添加了一个状态码200,如果不添加状态码SuperTest会将所有HTTP错误传递到第一个参数中。
如果使用了.end()方法,当.expect()断言中发生错误则不会抛出,而是会传递到.end()方法的回调函数中。所以,你可以像下面这样在.end()方法中重新跑出或使用done()回调:
describe('GET /users', function(){
it('respond with json', function(done){
request(app)
.get('/user')
.set('Accept', 'application/json')
.expect(200)
.end(function(err, res){
if (err) return done(err);
done();
});
});
});
异常捕获是依次进行的,可以在断言发生前修改response响应体或响应头:
describe('GET /user', function(){
it('user.name should be an case-insensitive match for "tobi"', function(done){
request(app)
.get('/user')
.set('Accept', 'application/json')
.expect(function(res) {
res.body.id = 'some fixed id';
res.body.name = res.body.name.toUpperCase();
})
.expect(200, {
id: 'some fixed id',
name: 'TOBI'
}, done);
});
});
任何HTTP操作都可以在super-agent中进行。如,可以模拟一个文件上传操作:
request(app)
.post('/')
.field('name', 'my awesome avatar')
.attach('avatar', 'test/fixtures/homeboy.jpg')
...
每次都传入一个app或url是不必要的,如果你的测试相同的主机名(域名)时,可以简单地重新初始化请求路径即可,然后一个新的测试实例会在每一个request.VERB()前创建:
request = request('http://localhost:5555');
request.get('/').expect(200, function(err){
console.log(err);
});
request.get('/').expect('heya', function(err){
console.log(err);
});
在HTTP中,总会使用cookie来保持会话状态。下面是一个在Mocha框架中使用cookie的示例:
var request = require('supertest')
, should = require('should')
, express = require('express');
describe('request.agent(app)', function(){
var app = express();
app.use(express.cookieParser());
app.get('/', function(req, res){
res.cookie('cookie', 'hey');
res.send();
});
app.get('/return', function(req, res){
if (req.cookies.cookie) res.send(req.cookies.cookie);
else res.send(':(')
});
var agent = request.agent(app);
it('should save cookies', function(done){
agent
.get('/')
.expect('set-cookie', 'cookie=hey; Path=/', done);
})
it('should send cookies', function(done){
agent
.get('/return')
.expect('hey', done);
})
})
3. API
supertest基于super-agent构建。在测试时,我们可以使用这个模块的一些底层的API。
.expect(status[, fn])-断言一个HTTP响应状态码.expect(status, body[, fn])-断言一个HTTP响应状态码及响应体.expect(body[, fn])-断言HTTP响应体(字符串、正则表达式或对象).expect(field, value[, fn])-断言HTTP头中的字段名与字段值(字符串、正则表达式).expect(function(res) {})-使用自定义的断言函数,它会对响应对象进行检查。request(app) .get('/') .expect(hasPreviousAndNextKeys) .end(done); function hasPreviousAndNextKeys(res) { if (!('next' in res.body)) return "missing next key"; if (!('prev' in res.body)) throw new Error("missing prev key"); }.end(fn)-断言一个HTTP响应状态码.expect(status[, fn])-执行请求并调用回调函数fn(err, res)
