我正在学习express和sinon(困难的方法:)。我想对以下代码进行单元测试。
// ./routers/root.js
var express = require('express');
var router = express.Router();
router
.route('/')
.get(function(req, res) {
res.writeHead(200, {'Content-Type': 'application/json'});
res.write(JSON.stringify({Application: "NodeTours", Version: "2.0.0", Host: host, Port: port}));
res.end();
});
module.exports = router;
我尝试了不同的方法,但都没有成功。我又回到了基本的例子上。我意识到这可能看起来像一个完整的新手问题,但我毫无头绪。这是最新的尝试。
// ./test/test.js
var sinon = require('sinon')
var expect = require('chai').expect
describe('Routers', function() {
context('/', function() {
var rootRouter = require('../routers/root')
var res = {Application: "NodeTours", Version: "2.0.0", Host: 'host', Port: 'port'};
it('should call / router', function() {
rootRouter.route('/').get(null, res);
// TODO: expect...
})
})
})
它失败了
Routers
/
1) should call / router
0 passing (4ms)
1 failing
1) Routers
/
should call / router:
Error: Route.get() requires a callback function but got a [object Null]
at Route.<computed> [as get] (node_modules/express/lib/router/route.js:202:15)
at Context.<anonymous> (test/test.js:10:29)
at processImmediate (internal/timers.js:456:21)
我试过很多教程,但都没有成功。我希望得到任何关于如何对我的代码进行单元测试的提示。或者如何调整我的代码,使单元测试更容易实现。
我的主应用程序server.js文件,供上下文和参考(删除了与本问题无关的代码)
// ./server.js
// npm pacakages
var express = require('express');
var bodyParser = require('body-parser');
// app imports
var { rootRouter } = require('./routers');
// other cut out
//globals
app = express();
app.use(bodyParser.json());
app.use('/', rootRouter);
// other cut out
// Set up Mongo DB connection
// code to st up db connection
// Start server (only if connection to DB established)
var server = MongoClient(url, { useUnifiedTopology: true, poolSize: 10 }).connect().then(client => {
const dbo = client.db(dbName);
// some init code cut out
// make connection available
app.locals.dbo = dbo;
// start server
app = app.listen(process.env.PORT || 7777, function () {
host = require('os').hostname();
port = "7777";
logger.verbose("Startup: NodeTours listening at http://%s:%s", host, port)
});
}).catch(error => {
logger.error("Startup: Couldn't connect to the DB. The app will exit")
logger.error(" Error: " + error)
process.exit();
}
);
在你的测试案例中,你试图直接调用GET处理程序。
it('should call / router', function() {
rootRouter.route('/').get(null, res);
// TODO: expect...
})
但是 appRouter.route('').get() 是一种方法,旨在 安装 请求处理程序,而不是调用它。这就是为什么你得到的错误说。
错误: Route.get()需要一个回调函数,但得到了一个[对象Null]。
也就是说,你是通过 null
为你认为是请求参数的东西,但Express期望它是一个方法(回调)处理程序。
通常我会把处理程序定义为非匿名函数。
function rootHandler(req, res) {
res.writeHead(200, {'Content-Type': 'application/json'});
res.write(JSON.stringify({Application: "NodeTours", Version: "2.0.0", Host: host, Port: port}));
res.end();
}
router
.route('/')
.get(rootHandler);
...然后单元测试可以直接调用函数,而不是通过Express(因为通常我们感兴趣的是测试我们自己的代码,而不是框架)。
it('should do something with root handler', function() {
rootHandler(null, res);
// TODO: expect...
})
如果你真的想测试路由逻辑,那就可以使用 supertest
的建议是一个不错的选择。
目前,我最终做了以下修改。
1) 修改了路由器的代码,把controllerhandler逻辑移到了外面。
// ./routers/root
var express = require('express');
var router = express.Router();
var rootController = require('../controllers/root')
router
.route('/')
.get(rootController.root_get);
module.exports = router;
2) 在单独的文件中加入controllerhandler逻辑。
// ./controllers/root
var logger = require('../utilities/loggers')
exports.root_get = function(req, res) {
res.writeHead(200, {'Content-Type': 'application/json'});
res.write(JSON.stringify({Application: "NodeTours", Version: "2.0.0", Host: host, Port: port}));
res.end();
}
3)实现了这样的测试。
var sinon = require('sinon')
var expect = require('chai').expect
describe('Controllers', function() {
context('/', function() {
var root = require('../controllers/root')
it('should call GET / controller', function() {
var res;
spy = root.root_get = sinon.spy()
root.root_get(null, res);
expect(spy.calledOnce).to.equal(true);
})
})
})
它的执行情况良好
Controllers
/
✓ should call GET / controller
1 passing (5ms)
它只解决了我原来的部分问题,因为我想测试路由器的逻辑。我在另一个帖子上单独发了一个关于这部分的问题。