单元测试结束承诺链的函数

时间:2015-11-23 03:24:01

标签: javascript node.js unit-testing promise mocha

假设我在一个名为UserController的类中有一个函数,它在这些行中执行某些操作(其中userService.createUser()返回一个promise):

function createUser(req, res)
{
  const userInfo = req.body;

  userService.createUser(userInfo)
    .then(function(){res.json({message: "User added successfully"})})
    .fail(function(error){res.send(error)})
    .done();
}

如何测试,当promise解析时,res.json()被调用,当promise拒绝时,res.send(error)被调用?

我尝试过写这样的测试:

const userService = ...
const userController = new UserController(userService);
const response = {send: sinon.stub()};

...

const anError = new Error();
userService.createUser = sinon.stub().returns(Q.reject(anError));

userController.createUser(request, response);

expect(response.send).to.be.calledWith(anError);

但测试失败了" response.send从未被调用过#34;。我还尝试在调用res.send(error)之前记录一些内容,并且记录确实发生了。

我的猜测是expect()在执行res.send(error)之前被调用,因为它是异步的。

我对承诺和单元测试相当新,是我的架构还是我对承诺的使用?

我使用Q代表承诺,使用mocha,chai,sinon进行单元测试。

2 个答案:

答案 0 :(得分:2)

当您进行异步调用时,expect行后面会调用userController.createUser()语句。因此,当评估断言时,它尚未被调用。

要异步测试代码,您需要在done语句中声明it,然后手动调用以获得结果。

在您的测试文件中:

it('should work', function(done) {
  ...
  userController.createUser(request, response);

  process.nextTick(function(){
    expect(response.send).to.be.calledWith(anError);
    done();
  });
});  

这将使Mocha(我假设您正在使用它)在excpect被调用时评估您的done()

或者,您可以在UserController.createUser函数上设置cb函数,并在.done()上调用它:

<强> UserController中

function createUser(req, res, cb) {
  const userInfo = req.body;

  userService.createUser(userInfo)
    .then(function(){res.json({message: "User added successfully"})})
    .fail(function(error){res.send(error)})
    .done(function(){ if(cb) cb() });
  }

然后进行测试:

userController.createUser(request, response, function() {
  expect(response.send).to.be.calledWith(anError);
  done();
});

答案 1 :(得分:1)

假设你使用Mocha或Jasmine作为框架,更简单的方法是在你刚开始时继续,但是完全跳过Sinon(因为这里不需要,除非你测试收到的实际参数):

// observe the `done` callback - calling it signals success
it('should call send on successful service calls', (done) => {
  // assuming  same code as in question
  ... 

  const response = {send: done};
  userController.createUser(request, response);
});


// observe the `done` callback - calling it signals success
it('should call send on failing service calls', (done) => {
  // assuming  same code as in question
  ... 

  const response = {send: err => err? done(): done(new Error("No error received"))};
  userController.createUser(request, response);
});

披露:我是Sinon维护团队的一员。