【问题标题】:Sinon crypto stub for method within a callback回调中方法的 Sinon 加密存根
【发布时间】:2019-04-04 00:54:22
【问题描述】:

我正在尝试测试一个使用 nodejs 加密库生成随机名称的简单函数。我正在使用 sinon 在 pseudoRandomBytes 的回调中存根方法调用,但似乎没有调用存根。示例:

getFileName.js

const crypto = require('crypto');

module.exports = (req, file, cb) => {
  crypto.pseudoRandomBytes(32, (err, raw) => {
    try{
      cb(err, err ? undefined : crypto.createHash('MD5').update(raw).digest('hex'));
    } catch(err) {
      cb(err);
    }
  });
};

测试(在 mocha 中运行)

it('Crypto Error: createHash', function () {
  const crypto = require('crypto');
  const expectedError = new Error('stub error occurred');
  let cryptoStub = sinon.stub(crypto, 'createHash').throws(expectedError);
  let callback = sinon.spy();

  getFileName(null, null, callback);

  cryptoStub.restore();
  sinon.assert.calledWith(callback, expectedError);
});

我希望一旦createHash 被调用,上述测试就会抛出。如果我将crypto.createHash 调用移到回调之外(在pseudoRandomNumber 调用之前),它就可以正常工作。我有点新手,所以我对 sinon 和 nodejs 正在做什么的基本理解可能是完全错误的。任何帮助将不胜感激。

【问题讨论】:

  • 你使用什么测试框架?
  • 我在用摩卡

标签: javascript node.js sinon


【解决方案1】:

看起来createHash() 没有被调用的原因是因为异步函数,您在回调调用完成之前进行了断言。

使用 async/await 的 Promise 会起作用。另一种不涉及更改模块以使用 Promise 的方法是在回调中进行断言。

it('Crypto Error: createHash', function (done) {
  const crypto = require('crypto');
  const expectedError = new Error('stub error occurred');
  let cryptoStub = sinon.stub(crypto, 'createHash').throws(expectedError);

  getFileName(null, null, function (err, hash) {
    sinon.assert.match(err, expectedError);
    cryptoStub.restore();
    done();
  });
});

这样,您可以检查调用回调时是否出现预期错误。确认这一点的一种方法是将第 4 行更改为.throws('some other error'),测试将失败。

【讨论】:

  • 确实,在回调中断言并不涉及更新他的模块,但是我强烈建议移动他的代码以使用 Promise。不仅用于测试(它会生成更清晰的代码),而且还用于每当他使用他的模块时 - 否则在不涉及意大利面条代码的情况下进行后续调用会更加困难
  • @Gonzalo.- 我同意。只是问题中特别提到了回调。
【解决方案2】:

问题在于crypto.pseudoRandomBytes() 是一个异步函数,因此您的测试代码的其余部分在您的回调之前执行。这样,您的存根在您的函数实际使用之前就已恢复。

为了让它正常工作,你应该更新你的getFileName.js,让它返回一个承诺——这样你就可以await it

module.exports = (req, file, cb) => {
    return new Promise((resolve, reject) => {
        crypto.pseudoRandomBytes(32, (err, raw) => {
            try{
                cb(err, err ? undefined : crypto.createHash('MD5').update(raw).digest('hex'));
                resolve();
            } catch(err) {
              reject(cb(err));
            }
        });
    });
};

然后在你的测试中

// added async
it('Crypto Error: createHash', async () => {
  const crypto = require('crypto');
  const expectedError = new Error('stub error occurred');
  let cryptoStub = sinon.stub(crypto, 'createHash').throws(expectedError);
  let callback = sinon.spy();

  await getFileName(null, null, callback);
  // once we are here, the callback has already been executed and the promise that getFileName resolved.
  cryptoStub.restore();
  sinon.assert.calledWith(callback, expectedError);
});

【讨论】:

    猜你喜欢
    • 2016-02-18
    • 2020-07-23
    • 2015-11-28
    • 1970-01-01
    • 2016-01-02
    • 1970-01-01
    • 2014-07-12
    • 2021-06-10
    • 1970-01-01
    相关资源
    最近更新 更多