摩卡& Sinon - 窥探从Node异步回调中调用的函数?

时间:2015-10-21 16:28:57

标签: javascript node.js mocha sinon chai

问题摘要:我想测试redisCallback(),它是在NodeJS Async回调中调用的(参见下面的代码),已使用预期的参数调用预期的数字时间。

背景信息(如果TL; DR则跳过):

我搜索过但只找到了QUnit的解决方案。我不确定Mocha + Sinon对于这种困境的等价物是什么。

在我目前的测试中,Chai断言以AssertionError: expected false to equal true回复。

但是,我通过调用this.redisCallback函数(正在测试中)updateRedis但在redisClient.get异步回调之外,在本例中为测试来测试套件正确检测到回调已被触发并且我的测试成功。

这告诉我的是这是一个异步问题。在redisClient.get回调完成之后,我如何告诉Mocha / Chai等待检查断言?

代码

编写此代码是为了解决Node的问题,我需要检查Redis中的某个键是否与系统命令返回的值不同,如果它已更改,请在Redis中设置新值。由于系统命令值将在异步调用的包含范围内(因此,不可访问/不可靠),我创建了一个函数,它返回我想要的redisClient.get回调的回调,但是将使用的密钥和系统命令值传递给用于记忆回调值的闭包。

与我使用HighlandJS编写的内容很接近:

var redisClient = require('redis').createClient(config.redis.port, config.redis.host),
    _ = require('highland');

// ...

redisCallback = function (resultsHash, redisKey, redisGetValue) {
  var systemCmdValue = resultsHash[redisKey];
  if (redisGetValue != systemCmdValue) {
      redisClient.set(redisKey, systemCmdValue, function (err) { // handle errors });
  }
};

// ...

updateRedis = function (err, stdout, stderr) {
  // Do some stuff that's not important to this problem

  var resultsHash = parseCmdResults(stdout),
      redisKeys = Object.keys(resultsHash),
      curriedRedisCallback = _.curry(this.redisCallback, resultsHash);
      get = _.wrapCallback(redisClient.get.bind(redisClient));

  redisKeys.each(function (key) {
    get(key).each(curriedRedisCallback(key));
  });
};

vanilla NodeJS和JavaScript中的等效实现:

var redisClient = require('redis').createClient(config.redis.port, config.redis.host);

// ...

redisCallback = function (resultsHash, redisKey, redisGetValue) {
  var systemCmdValue = resultsHash[redisKey];
  if (redisGetValue != systemCmdValue) {
    redisClient.set(redisKey, systemCmdValue, function (err) { // handle errors });
  }
};

redisCallbackWrapper = function (resultsHash) {
  return function (redisKey) {
    return function (redisGetValue) {
      this.redisCallback(resultsHash, redisKey, redisGetValue);
    };
  };
};

// ...

updateRedis = function (err, stdout, stderr) {
  // Do some stuff that's not important to this problem

  var resultsHash = parseCmdResults(stdout),
      redisKeys = Object.keys(resultsHash),
      callback = redisCallbackWrapper(resultsHash),
      key;

  for (var i = 0; i < redisKeys; i++) {
    key = redisKeys[i];
    redisClient.get(key, callback(key));
  }
};

我使用Mocha,Chai和Sinon的测试:

describe('when valid arguments are provided to updateRedis', function () {
  var err, stdout, stderr, parsedStdout, key0, key1;

  before(function () {
    err = undefined;
    stderr = undefined;
    stdout = 'key0/value0\nkey1/value1';
    key0 = 'key0';
    key1 = 'key1';
    parsedStdout = {};
    parsedStdout[key0] = "value0";
    parsedStdout[key1] = "value1";

    sinon.spy(myModule, 'redisCallback');
  });

  after(function () {
    myModule.redisCallback.restore();
  });

  it('calls redisCallback with the expected arguments the expected number of times', function (done) {
    myModule.updateRedis(err, stdout, stderr);
    // If I can get to the point where it's detected that redisCallback has been called at all,
    // I can follow the documentation to figure out how to test that it's called with the expected args the expected number of times.
    expect(myModule.redisCallback.called).to.equal(true);
    done();
  });
});

0 个答案:

没有答案