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)