如何使用sinon

时间:2016-04-07 13:09:22

标签: javascript testing sinon

我对mocha / chai / sinon很新,并且测试一般。我成功地测试了一个基本的快递服务器,一个返回承诺的功能,以及一个基本的续集设置让我的鼻子湿透;但我被困在间谍/存根/嘲笑上。

我的拳头打嗝试图检查外部模块中是否已调用glob:

//in utils.js
var glob = require('glob');

module.exports = {
  funToTest: function (msg, callback) {
    console.log(msg);
    glob('*md', {
      cwd: 'files/'
    }, function (err, files) {
      console.log(files);
    });
    callback();
    callback();
  }
};

使用mocha / chai / sinon / sinon-chai组合:

// in utils-test.js
var utils = require('utils.js');
var glob = require('glob');

describe('Utils', function () {
  describe('funToTest method', function () {
    const callback = sinon.spy();
    const globSpy = sinon.spy(glob);

    before(function (done) {
      utils.funToTest('Files:', callback);
      done();
    });

    // This PASSES fine
    it ('should call our callback twice', function () {
      expect(callback).to.have.been.calledTwice;
    });

    // This NOT SO MUCH
    it('should call glob once', function () {
      expect(globSpy).to.have.been.calledOnce;
    });
  )};
)};

以上内容因断言错误而失败:

AssertionError: expected glob to have been called exactly once, but it was called 0 times

那么如何监视utils.funToTest中的glob依赖关系以查看是否被调用?

感谢任何指针......

2 个答案:

答案 0 :(得分:0)

您正在监视glob模块本身,而不是funToTest方法中的glob调用。问题是glob调用是一个实现细节,实际上无法从测试中访问。你需要为glob回调传递一个参数,并测试它是用间谍或存根调用的。

//in utils.js
var glob = require('glob');

module.exports = {
  funToTest: function (msg, globCb, callback) {
    glob('*md', {
      cwd: 'files/'
    }, globCb);
    callback();
    callback();
  }
};

// in utils-test.js
var utils = require('utils.js');
var glob = require('glob');

describe('Utils', function () {
  describe('funToTest method', function () {
    const callback = sinon.spy();
    const globCb = sinon.spy();

    const err = {err: 'Error'};
    const files = ['file1', 'file2'];

    before(function (done) {
      utils.funToTest('Files:', globCb, callback);
      done();
    });

    // Should still pass
    it ('should call our callback twice', function () {
      expect(callback).to.have.been.calledTwice;
    });

    // Passes with correct args
    it('should call glob once', function () {
      expect(globCb).to.have.been.calledOnce;
      // inspect the arg values with .calledWithArgs
      expect(globCb.calledWithArgs(err, files)).to.be.true;
      // inspect the arg values with .getCall(index) (actually grabs the call args on the first call to globSpy)
      expect(globCb.getCall(0).args[0]).to.equal(err);
      expect(globCb.getCall(0).args[1]).to.equal(files);
    });
  )};
)};

答案 1 :(得分:0)

这是使用附加库proxyquire的单元测试解决方案:

utils.js

const glob = require("glob");

module.exports = {
  funToTest: function(msg, callback) {
    console.log(msg);
    glob(
      "*md",
      {
        cwd: "files/",
      },
      function(err, files) {
        console.log(files);
      },
    );
    callback();
    callback();
  },
};

utils.test.js

const proxyquire = require("proxyquire");
const sinon = require("sinon");

describe("36477213", () => {
  afterEach(() => {
    sinon.restore();
  });
  it("should pass", () => {
    const logSpy = sinon.spy(console, "log");
    const files = ["a", "b"];
    const globStub = sinon.stub().yields(null, files);
    const utils = proxyquire("./utils.js", {
      glob: globStub,
    });
    const callback = sinon.stub();
    utils.funToTest("some message", callback);
    sinon.assert.calledWith(globStub, "*md", { cwd: "files/" }, sinon.match.func);
    sinon.assert.calledTwice(callback);
    sinon.assert.calledWith(logSpy.firstCall, "some message");
    sinon.assert.calledWith(logSpy.secondCall, files);
  });
});

覆盖率100%的单元测试结果:

  36477213
some message
[ 'a', 'b' ]
    ✓ should pass


  1 passing (24ms)

---------------|----------|----------|----------|----------|-------------------|
File           |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
---------------|----------|----------|----------|----------|-------------------|
All files      |      100 |      100 |      100 |      100 |                   |
 utils.js      |      100 |      100 |      100 |      100 |                   |
 utils.test.js |      100 |      100 |      100 |      100 |                   |
---------------|----------|----------|----------|----------|-------------------|

源代码:https://github.com/mrdulin/mocha-chai-sinon-codelab/tree/master/src/stackoverflow/36477213