Sinon Spies-测试递归(可能是const)函数表达式

时间:2018-08-05 17:22:37

标签: javascript mocha sinon

我正在与Sinon一起使用Mocha,并尝试测试递归调用(fibonacci)。我的代码是:

'use strict';

let sinon = require('sinon'),
    chai = require('chai'),
    expect = chai.expect;

chai.use(require('sinon-chai'));

let fib = function (n) {
    if (n === 0) {
        return 0;
    } else if (n === 1) {
        return 1;
    } else {
        return fib(n-2) + fib(n-1);
    }
};

describe('fib', function() {
        it('should repeat calculations', function() {
            let originalFib = fib;
            fib = sinon.spy(fib)

            expect(fib(6)).to.equal(8);
            expect(fib).to.have.callCount(25);

            fib = originalFib;
        });
});

此代码按原样工作,但是,如果我替换以下行:

let fib = function (n) {

具有:

const fib = function (n) {

我收到以下错误:

TypeError:分配给常量变量。

这符合预期,但提出了一个问题,我将如何测试使用Sinon声明为const的递归函数?

编辑 Jasmine有一个名为.callThrough()的东西,它似乎允许测试递归函数。

在我看来,没有办法与Sinon重复这种行为吗?我查看了以下错误报告/功能请求:

https://github.com/sinonjs/sinon/issues/668

https://github.com/sinonjs/sinon/issues/989

谢谢。

2 个答案:

答案 0 :(得分:2)

直接在函数上调用sinon.spy会在原始函数周围创建一个包装器,该包装器可跟踪调用和返回的值,但不会对其进行修改,因此您无需记住它并恢复它。

有了这些信息,显而易见的答案就是简单地给你的间谍起个别的名字:

describe('fib', function() {
  it('should repeat calculations', function() {
    const spy = sinon.spy(fib);

    expect(spy(6)).to.equal(8);
    expect(spy).to.have.callCount(25);
  });
});

这种方法对非递归函数很好用,但是您可能会注意到,虽然第一个断言通过了,但是第二个失败了,只进行了一次间谍调用。

问题在于,这里还有另外一个问题。函数fib直接调用自身,并且通过用sinon.spy包装该函数不会跟踪那些直接的递归调用。

the answer here中提供了有关此问题的更多详细信息以及相应的解决方案。

答案 1 :(得分:0)

将代码更改为const fib = function(n)时的主要问题是因为您拥有此后续代码fib = sinon.spy(fib)。我们无法使用const重新声明任何变量的赋值。

对于这种测试,根据我的经验,我觉得没有必要使用spy,除非您有其他函数可以在fib内调用。我们可以执行并检查所有可能情况的值。

'use strict';

const sinon = require('sinon'),
      chai = require('chai'),
      expect = chai.expect;

chai.use(require('sinon-chai'));

const fib = function (n) {
  if (n === 0) {
    return 0;
  } else if (n === 1) {
    return 1;
  } else {
    return fib(n - 2) + fib(n - 1);
  }
};

describe('fib', function () {
  it('should repeat calculations', function () {
    expect(fib(0)).to.equal(0); // add more cases
    expect(fib(1)).to.equal(1);
    expect(fib(6)).to.equal(8);
  });
});

希望有帮助。