node.js express route/controller 中基于承诺的单元测试代码

Unit testing promise based code in node.js express route/controller

最近,我在其余 api Express 应用程序中从使用回调切换到使用 Promise。 但是我在使用 promise 的异步行为进行单元测试 routes/controller 时遇到了麻烦。这是需要进行单元测试的示例代码。

var handler =  function (req, res, next) {
  var query = {}, 
  var options = {
    sort: { updatedAt: -1 },
    limit: 10
  };
  if (req.query.before) {
    query.updatedAt = { $lt: req.query.before };
  }
  // User.findAsync returns bluebird promise
  User.findAsync(query, null, options).then(function (user) {
    res.json(user);
  }).catch(function (e) {
    next(e);
  });
}
router.get('/api/users', handler);

我测试上述代码的方法是监视 req、next 和 User.findAsync 并检查它们是否使用正确的参数调用。但是由于承诺的异步行为,我无法检查 res.json 或 next 是否被调用。

我试图将 findAsync 存根到 return 已解决的承诺(Promise.resolve(用户))。但仍然异步执行回调。

我不确定我是否在测试 express 应用程序的正确轨道上。

在良好分离中测试这种代码的好策略是什么?

我也听说过使用超级测试。 但对我来说,使用 supertest 从 http 端点进行测试感觉更像是集成测试,它不是单元测试,而且非常昂贵。

此外,一般来说,我想知道尝试用单元测试(模型、控制器、中间件等)覆盖所有代码是否是一种好的做法,以及这样做的好的策略或技巧是什么。或者如果用 super test 来测试 http 端点就足够了。

如果您的测试方法没有 return promise,那么您不能在 Mocha 中使用 promise 语法。您可以像测试任何其他异步方法一样测试您的方法 - 使用 done 作为 it 的参数。假设我们要测试您的 handler 函数:

var handler =  function (req, res, next) {
  //...
  User.findAsync(query, null, options).then(function (user) {
    res.json(user);
  }).catch(function (e) {
    next(e);
  });
}

我们可以这样写一个测试:

describe("The handler", function(){
     it("calls res.json", function(done){ // note the done argument
         handler({query: {before: 5}, // mock request
                 {json: done} // res.json calls our `done` param of this function
                 function(){ throw new Error("error called"); });
     });
});

请注意,我们模拟了请求、响应和 next 处理程序。我们的模拟响应有一个 json 方法,让测试知道它已完成(如果您想在其中进行断言,这可以是一个函数)并且如果 next 被调用而不是我们抛出信号它不是应该发生的事情。