【问题标题】:Unit test a function that ends the promise chain单元测试结束 Promise 链的函数
【发布时间】:2016-02-25 02:25:46
【问题描述】:

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

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 is never called”。我还尝试在调用 res.send(error) 之前记录一些内容,并且记录确实发生了。

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

我对 Promise 和单元测试还很陌生,这与我的架构或我对 Promise 的使用有关吗?

我将 Q 用于 Promise,使用 mocha、chai、sinon 进行单元测试。

【问题讨论】:

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


    【解决方案1】:

    当您进行异步调用时,expect 语句将在 userController.createUser() 行之后立即调用。所以当断言被评估时,它还没有被调用。

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

    在您的测试文件上:

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

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

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

    用户控制器

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

    【讨论】:

    • 使用process.nextTickdone() 完成了工作!谢谢!
    【解决方案2】:

    假设您使用 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 维护团队的一员。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-10-17
      • 1970-01-01
      • 2016-03-10
      • 2021-12-23
      • 1970-01-01
      • 1970-01-01
      • 2018-05-13
      相关资源
      最近更新 更多