node.js中的单元测试承诺基于代码表示路由/控制器

时间:2015-02-06 20:45:54

标签: node.js unit-testing express promise bluebird

最近我在我的rest api express app中使用回调切换到使用promise。 但我遇到了单元测试路由/控制器与承诺异步行为的问题。以下是需要进行单元测试的示例代码。

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存根以返回已解析的promise(Promise.resolve(user))。但仍然会以异步方式执行回调。

我不确定我是否正在测试快递应用程序。

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

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

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

1 个答案:

答案 0 :(得分:4)

如果您测试的方法未返回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而不是我们抛出信号它不是假设的东西即将发生。