unit testing结束承诺链的function

假设我在一个名为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(); } 

我怎样才能testing,当承诺解决, res.json()被调用,当承诺拒绝, res.send(error)被调用?

我已经尝试写这样的testing:

 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); 

但testing失败,“response.send永远不会被调用”。 我也试过在调用res.send(error)之前logging一些东西,并且logging发生了。

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

我在承诺和unit testing方面还是比较新的,这是我的架构还是我对promise的使用?

我使用Q来承诺和摩卡,柴,我的unit testing。

由于你有一个asynchronous调用,在userController.createUser()行之后调用expect语句。 所以当断言被评估时,它还没有被调用。

要asynchronoustesting你的代码,你将需要在你的it语句中声明done ,然后手动调用它来获得结果。

在你的testing文件上:

 it('should work', function(done) { ... userController.createUser(request, response); process.nextTick(function(){ expect(response.send).to.be.calledWith(anError); done(); }); }); 

这将使摩卡(我假设你正在使用它)评估你的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() }); } 

然后在你的testing中:

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

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

 // 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维护团队的一员。