使用 Supertest 测试 Express.js 应用
supertest提供了简单易用的客户代理,可以方便地用来测试Express.js应用。
本文介绍如何在Mocha中使用supertest,
以及测试 Express.js 应用涉及到的一些问题:
包括如何在每个测试项之前正确地关闭上一个Express.js Server,
以及如何避免require
缓存造成的环境差异。
关于如何使用Mocha测试Node.js代码,请参考利用 Mocha 进行 BDD 风格测试一文。
一个简易的Express应用
先来写一个简单的Express应用,绑定/
目录并返回200 harttle
。
下文中便来讨论如何正确地测试该应用。
var express = require('express');
var app = express();
app.get('/', function (req, res) {
res.status(200).send('harttle');
});
var server = app.listen(3000, function () {
var port = server.address().port;
});
module.exports = server;
Supertest
supertest
提供了.get()
, .expect()
等方法来测试 Express server
。
下面给出一个简单的supertest
使用示例。
文档:https://github.com/visionmedia/supertest
var request = require('supertest');
describe('loading express', function () {
var server;
beforeEach(function () {
server = require('./server');
});
afterEach(function () {
server.close();
});
it('responds to /', function testSlash(done) {
request(server)
.get('/')
.expect(200, done);
});
it('404 everything else', function testPath(done) {
request(server)
.get('/foo/bar')
.expect(404, done);
});
});
正确关闭 Express
通常我们希望每项测试都在初始的环境中进行,
于是在每项测试后使用server.close()
关闭服务器,
在每项测试前使用server = require('./server')
重新开启。
然而server.close()
不会立即关闭服务器,这使得测试中常发生EADDRINUSE
错误。
但server.close()
可以接受一个回调来通知服务器正确关闭事件。
可以利用该回调来使Mocha顺序执行异步过程。只需要将afterEach
改为:
afterEach(function (done) {
server.close(done);
});
清除 require 缓存
尽管我们重启了Expressserver
,当require('./server')
时Node.js
仍然会返回上次require
的缓存。通常的实践中应当用工厂方法来解决,
比如给出makeServer()
方法:
function makeServer() {
var express = require('express');
var app = express();
app.get('/', function (req, res) {
res.status(200).send('harttle');
});
var server = app.listen(3000, function () {
var port = server.address().port;
console.log('Example app listening at port %s', port);
});
return server;
}
module.exports = makeServer;
这样每次调用makeServer()
都会重新执行上述代码。
然而为了写测试去更改代码结构有时并不可行,正确的方式是通过Node.js API来清除缓存:
beforeEach(function () {
delete require.cache[require.resolve('./server')];
server = require('./server');
});
其实有一个NPM库really-need已经封装了上述代码,导入该工具即可覆盖require
的默认行为。
require = require('really-need');
beforeEach(function () {
server = require('./server', { bustCache: true });
});
最终代码
最终的测试代码如下:
var request = require('supertest');
require = require('really-need');
describe('loading express', function () {
var server;
beforeEach(function () {
server = require('./server', { bustCache: true });
});
afterEach(function (done) {
server.close(done);
});
it('responds to /', function testSlash(done) {
request(server)
.get('/')
.expect(200, done);
});
it('404 everything else', function testPath(done) {
request(server)
.get('/foo/bar')
.expect(404, done);
});
});
本文翻译自:https://glebbahmutov.com/blog/how-to-correctly-unit-test-express-server/
本文采用 知识共享署名 4.0 国际许可协议(CC-BY 4.0)进行许可,转载注明来源即可: https://harttle.land/2016/07/28/testing-express.html。如有疏漏、谬误、侵权请通过评论或 邮件 指出。