简体   繁体   English

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

[英]Test callback invocation at the end of promise chain

I am dealing with a code mixing node-style callbacks and Bluebird promises, and I need to write some unit tests for it. 我正在处理将节点样式的回调和Bluebird Promise混合在一起的代码,我需要为此编写一些单元测试。

In particular, cache.js exposes the init() function, which works with promises. 特别是, cache.js公开了init()函数,该函数可与promises一起使用。 It is then called by the doSomething() function in another file (eg index.js ) which in turn accepts a callback that has to be invoked at the end of init() . 然后,由另一个文件(例如index.js )中的doSomething()函数调用它,该文件又接受必须在init()末尾调用的回调。

Pseudocode is as follows: 伪代码如下:

// [ 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');
}

A possible unit test could be (showing only relevant code): 可能的单元测试为(仅显示相关代码):

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

This test passes, however changing the expectation to not.have.been.calledOnce also passes, which is wrong. 该测试通过了,但是将期望值更改为not.have.been.calledOnce也通过了,这是错误的。

Also, console logs are out of sequence: 另外,控制台日志不正确:

Enter
Exit
Invoking callback

I have looked at several possibilities, none of which worked: 我研究了几种可能性,没有一种可行:

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

  • Refactoring doSomething() to be simply: doSomething()重构为简单的:

    function doSomething(callback) { cache.init() .asCallback(callback); 函数doSomething(callback){cache.init().asCallback(callback); } }

Can anyone help me understand what I am doing wrong and how I can fix it please? 谁能帮助我了解我在做什么错以及如何解决?

console logs are out of sequence 控制台日志不正确

The logs are in the correct order because your Promise will be async meaning, at the very least, the internal console logs calls in then & catch will run on the next tick. 日志的顺序正确,因为您的Promise将会是异步的,至少,内部控制台会在该日志中记录调用, then catch会在下一个刻度上运行。

As to why the test is failing is the result of a couple of issues, first one is you don't appear to have sinon-chai configured correctly, or at best your calledOnce assertion isn't kicking in. Just to confirm, the top of your test file should something like: 至于为什么测试失败是由几个问题导致的,首先是您似乎没有正确配置sinon-chai ,或者充其量是您calledOnce断言没有被执行。测试文件的内容应类似于:

const chai = require("chai");
const sinonChai = require("sinon-chai");

chai.use(sinonChai);

If you have that and it's still not working correctly then might be worth opening an issue on the sinon-chai lib, however, a simple workaround is to switch to sinon assertions eg 如果您有该工具,但仍然无法正常工作,那么可能值得在sinon-chai lib上打开一个问题,但是,一种简单的解决方法是切换到sinon断言,例如

sinon.assert.calledOnce(callback)

Secondly, when you do eventually fix this, you'll probably find that the test will now fail...everytime. 其次,当您最终解决此问题时,您可能会发现该测试现在每次都会失败。 Reason being you've got the same problem in your test that you have with your logging - your asserting before the internal promise has had a chance to resolve. 原因是您在测试中遇到了与日志记录相同的问题-您在内部承诺有机会解决之前的断言。 Simplest way of fixing this is actually using your done handler from Mocha as your assertion 解决此问题的最简单方法实际上是使用Mocha中已done处理程序作为断言

mockCache.expects('init').resolves({});
doSomething(() => done());

In other words, if done get's called then you know the callback has been called :) 换句话说,如果done get的调用,则您知道回调已被调用:)

Following James ' comment I revisited my tests like this: 詹姆斯发表评论之后,我重新审视了我的测试:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM