如何使用 mocha 测试我的 express 应用程序?
Posted
技术标签:
【中文标题】如何使用 mocha 测试我的 express 应用程序?【英文标题】:How do i test my express app with mocha? 【发布时间】:2012-02-08 13:25:26 【问题描述】:我刚刚将 shouldjs 和 mocha 添加到我的 express 应用程序中进行测试,但我想知道如何测试我的应用程序。我想这样做:
app = require '../app'
routes = require '../src/routes'
describe 'routes', ->
describe '#show_create_user_screen', ->
it 'should be a function', ->
routes.show_create_user_screen.should.be.a.function
it 'should return something cool', ->
routes.show_create_user_screen().should.be.an.object
当然,该测试套件中的最后一个测试只是告诉我 res.render 函数(在 show_create_user_screen 中调用)未定义,可能是因为服务器未运行且配置尚未完成。所以我想知道其他人是如何设置测试的?
【问题讨论】:
只是想补充一下,上面的例子是因为它简短而简洁。通常我会测试在调用我的一个路由器函数之后设置/调用给定 req/res 对象上的适当函数或值。下面的答案就足够了。不应该测试路由器的功能,这是网络框架的工作。 【参考方案1】:好的,首先,虽然测试路由代码是您可能想做也可能不想做的事情,但一般来说,尝试将您感兴趣的业务逻辑分离为与 express 或任何框架分离的纯 javascript 代码(类或函数)正在使用和使用香草摩卡测试来测试它。一旦你实现了这一点,如果你想真正测试你在 mocha 中配置的路由,你需要将 mock req, res
参数传递到你的中间件函数中,以模仿 express/connect 和你的中间件之间的接口。
对于一个简单的案例,您可以创建一个模拟 res
对象,其中包含一个类似于下面的 render
函数。
describe 'routes', ->
describe '#show_create_user_screen', ->
it 'should be a function', ->
routes.show_create_user_screen.should.be.a.function
it 'should return something cool', ->
mockReq = null
mockRes =
render: (viewName) ->
viewName.should.exist
viewName.should.match /createuser/
routes.show_create_user_screen(mockReq, mockRes).should.be.an.object
FYI 中间件函数也不需要返回任何特定值,这是它们对 req, res, next
参数所做的事情,您应该在测试中关注这些参数。
这是您在 cmets 中请求的一些 JavaScript。
describe('routes', function()
describe('#show_create_user_screen', function()
it('should be a function', function()
routes.show_create_user_screen.should.be.a["function"];
);
it('should return something cool', function()
var mockReq = null;
var mockRes =
render: function(viewName)
viewName.should.exist;
viewName.should.match(/createuser/);
;
routes.show_create_user_screen(mockReq, mockRes);
);
);
);
【讨论】:
模拟没有给您的一件事是防止您正在使用的模块的 api 更改。例如如果 express 更新并更改了渲染的名称,您将不受保护。理想情况下,您也在测试它,但有时集成+单元测试可以一次测试大量代码,这取决于您如何看待它,这是好事还是坏事。编辑:虽然我真的很喜欢这种模拟方法,但它真的很轻量级。 能不能总是加编译好的js,有些人不熟悉coffeescript。 这不是测试实现细节吗?您实际上想测试“响应”对象在返回时包含的内容 - 如果将来您不使用“渲染”方法来执行此操作,例如在重构期间,您的测试将失败并且不会向您显示重构的代码有效,因为您必须重写测试?只是一个想法 !否则,这是一种模拟响应对象的聪明方法。 Supertest 是另一种进行更多端到端测试的方法。两者都有其用途。【参考方案2】:你可以试试 SuperTest,然后服务器的启动和关闭都处理好了:
var request = require('supertest')
, app = require('./anExpressServer').app
, assert = require("assert");
describe('POST /', function()
it('should fail bad img_uri', function(done)
request(app)
.post('/')
.send(
'img_uri' : 'foobar'
)
.expect(500)
.end(function(err, res)
done();
)
)
);
【讨论】:
SuperTest 为我工作了至少十几个项目。为了胜利! 不知道supertest
和chaihttp
有什么区别?【参考方案3】:
在connect.js tests suites中找到了替代方案
他们使用supertest 来测试一个连接应用程序,而没有将服务器绑定到任何端口,也没有使用模型。
这是 connect 的静态中间件测试套件的摘录(使用 mocha 作为测试运行器,使用 supertest 作为断言)
var connect = require('connect');
var app = connect();
app.use(connect.static(staticDirPath));
describe('connect.static()', function()
it('should serve static files', function(done)
app.request()
.get('/todo.txt')
.expect('contents', done);
)
);
这也适用于快递应用
【讨论】:
我只能接受一个答案,否则也会被接受 =) app.request 在最新的 express/connect 中对我不起作用,所以我更新了这个答案以匹配github.com/visionmedia/supertest的用法 关于supertest
的条款看起来具有误导性。 connect code 中似乎没有提到它。无论如何,Alexandru 的答案看起来比其他人更好。
这里是使用supertest
的连接部分:github.com/senchalabs/connect/blob/…【参考方案4】:
我发现最简单的方法是设置一个 TestServer 类用作帮助器,以及一个 帮助 http 客户端,并且只是向真正的 http 服务器发出真正的请求。不过,在某些情况下,您可能想要模拟和存根这些东西。
// Test file
var http = require('the/below/code');
describe('my_controller', function()
var server;
before(function()
var router = require('path/to/some/router');
server = http.server.create(router);
server.start();
);
after(function()
server.stop();
);
describe("GET /foo", function()
it('returns something', function(done)
http.client.get('/foo', function(err, res)
// assertions
done();
);
);
);
);
// Test helper file
var express = require('express');
var http = require('http');
// These could be args passed into TestServer, or settings from somewhere.
var TEST_HOST = 'localhost';
var TEST_PORT = 9876;
function TestServer(args)
var self = this;
var express = require('express');
self.router = args.router;
self.server = express.createServer();
self.server.use(express.bodyParser());
self.server.use(self.router);
TestServer.prototype.start = function()
var self = this;
if (self.server)
self.server.listen(TEST_PORT, TEST_HOST);
else
throw new Error('Server not found');
;
TestServer.prototype.stop = function()
var self = this;
self.server.close();
;
// you would likely want this in another file, and include similar
// functions for post, put, delete, etc.
function http_get(host, port, url, cb)
var options =
host: host,
port: port,
path: url,
method: 'GET'
;
var ret = false;
var req = http.request(options, function(res)
var buffer = '';
res.on('data', function(data)
buffer += data;
);
res.on('end',function()
cb(null,buffer);
);
);
req.end();
req.on('error', function(e)
if (!ret)
cb(e, null);
);
var client =
get: function(url, cb)
http_get(TEST_HOST, TEST_PORT, url, cb);
;
var http =
server:
create: function(router)
return new TestServer(router: router);
,
client: client
;
module.exports = http;
【讨论】:
刚刚意识到我错过了你的问题的重点,但也许这无论如何都会有所帮助。我个人不会自己测试路由器功能。我只是通过 HTTP 请求测试服务器基本上完成了它应该做的事情,然后分别测试所有业务逻辑,因为它都在控制器之外的文件中。 您有对path/to/some/router
的引用,查看该文件的内容会很有帮助。【参考方案5】:
mocha 带有用于 bdd 测试的 before、beforeEach、after 和 afterEach。在这种情况下,您应该在 describe 调用中使用 before。
describe 'routes' ->
before (done) ->
app.listen(3000)
app.on('connection', done)
【讨论】:
以上是关于如何使用 mocha 测试我的 express 应用程序?的主要内容,如果未能解决你的问题,请参考以下文章
使用 Express、Socket.io 和 Node-Telegram-Bot-Api 结束 Mocha 测试
单元/集成测试 Express REST API, mongoose, mocha, sinon, chai, supertest
在 mocha 中,如何在执行另一个测试之前等待异步测试结束?
使用 mocha 测试 express 服务器并使用异步初始化程序进行 supertest 调用请求两次