【问题标题】:Unit testing express.js route with sinon使用 sinon 对 express.js 路由进行单元测试
【发布时间】:2020-08-13 15:55:14
【问题描述】:

我正在学习 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();
  }
);

【问题讨论】:

  • Idk 但如果您想轻松测试您的网络服务器,您可以使用包supertest 来模拟服务器并轻松发送请求并验证响应。
  • @MickaelB。我已经成功使用了 supertest,但我相信这将被归类为集成测试,而不是单元测试。
  • 是的,你是对的

标签: node.js unit-testing express sinon


【解决方案1】:

在您的测试用例中,您正尝试直接调用 GET 处理程序:

it('should call / router', function() {
  rootRouter.route('/').get(null, res);
  // TODO: expect...
})

appRouter.route('/').get() 是一种旨在安装请求处理程序的方法,而不是调用它。这就是为什么你得到的错误说:

错误:Route.get() 需要一个回调函数但得到了一个 [object 空]

也就是说,您传递 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...
})

如果你真的想测试路由逻辑,那么使用 cmets 中建议的supertest 是一个不错的选择。

【讨论】:

  • 顺便提一下,这篇 stackoverflow.com/a/48820849/925478 的帖子声称 Express 支持使用 app._router.handle 调用回调处理程序,但这似乎没有记录在案,我也没有亲自使用过。
  • 处理程序的好点。谢谢。这就是我在其他路线中所做的 - 我将路由器与控制器/处理程序分开,例如var express = require('express'); var router = express.Router(); var cruisesController = require ("../controllers/cruises"); router .route('/') .get(cruisesController.cruises_get) router .route('/:id') .get(cruisesController.cruises_get_id) module.exports = router;
  • 我把root.js改成了var express = require('express'); var router = express.Router(); 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); module.exports = router; })
  • 我的 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.rootHandler(null, res) }) }) })
  • 现在我得到Routers / 1) should call / router 0 passing (4ms) 1 failing 1) Routers / should call / router: TypeError: rootRouter.rootHandler is not a function at Context.&lt;anonymous&gt; (test/test.js:11:18) at processImmediate (internal/timers.js:456:21)
猜你喜欢
  • 2020-08-15
  • 2016-12-21
  • 2021-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-16
  • 1970-01-01
相关资源
最近更新 更多