在promise链的末尾测试回调调用

时间:2017-08-02 12:05:41

标签: javascript node.js callback bluebird sinon-chai

我正在处理混合节点式回调和Bluebird承诺的代码,我需要为它编写一些单元测试。

特别是,cache.js公开了init()函数,它与promises一起使用。然后由doSomething()函数在另一个文件(例如index.js)中调用它,该文件又接受必须在init()结束时调用的回调。

伪码如下:

// [ cache.js ]
function init() {
  return performInitialisation()
    .then((result) => return result);
}


// [ index.js ]
var cache = require('./cache');

function doSomething(callback) {
  console.log('Enter');

  cache.init()
    .then(() => {
      console.log('Invoking callback');
      callback(null);
    })
    .catch((err) => {
      console.log('Invoking callback with error');
      callback(err);
    });

  console.log('Exit');
}

可能的单元测试可能是(仅显示相关代码):

// [ index.test.js ]
...
var mockCache = sinon.mock(cache);
...
it('calls the callback on success', function(done) {
  mockCache.expects('init')
    .resolves({});

  var callback = sinon.spy();

  doSomething(callback);
  expect(callback).to.have.been.calledOnce;
  done();
});

此测试通过,但是将期望更改为not.have.been.calledOnce也会通过,这是错误的。

此外,控制台日志不按顺序排列:

Enter
Exit
Invoking callback

我已经研究了几种可能性,但没有一种可行:

  • 使用chai-as-promised,例如: expect(callback).to.eventually.have.been.calledOnce;

  • 重构doSomething()只是:

    function doSomething(callback){   cache.init()     .asCallback(回调); }

任何人都可以帮我理解我做错了什么以及如何解决它吗?

2 个答案:

答案 0 :(得分:0)

  

控制台日志不按顺序

日志的顺序正确,因为-(void)textFieldDidChange :(UITextField *)theTextField{ if (panNumber.length <= 5 || panNumber.length > 9) { [theTextField setKeyboardType:UIKeyboardTypeEmailAddress]; } else { [theTextField setKeyboardType: UIKeyboardTypeNumberPad]; } [theTextField reloadInputViews]; } 将是异步的意思,至少内部控制台会记录Promise&amp; then将在下一个刻度线上运行。

至于为什么测试失败是由于几个问题造成的,首先是你似乎没有正确配置catch,或者至多你的sinon-chai断言是&n& #39; t kicking in。只是为了确认,测试文件的顶部应该是这样的:

calledOnce

如果你有这个并且它仍然无法正常工作那么可能值得在const chai = require("chai"); const sinonChai = require("sinon-chai"); chai.use(sinonChai); lib上打开一个问题,但是,一个简单的解决方法是切换到sinon assertions,例如

sinon-chai

其次,当你最终解决这个问题时,你可能会发现测试现在每次都会失败。原因是您在测试中遇到了与日志记录相同的问题 - 在内部承诺有机会解决之前您的断言。最简单的解决方法是使用Mocha的sinon.assert.calledOnce(callback) 处理程序作为断言

done

换句话说,如果mockCache.expects('init').resolves({}); doSomething(() => done()); 被调用,那么您就知道已经调用了回调:)

答案 1 :(得分:0)

关注James'评论后,我重新审视了我的测试:

it('calls the callback on success', function(done) {
  mockCache.expects('init')
    .resolves({});

  doSomething(done);
});

it('calls the callback on error', function(done) {
  mockCache.expects('init')
    .rejects('Error');

  doSomething((err) => {
    if (err === 'Error') {
      done();
    } else {
      done(err);
    }
  });
});