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

Sinon Spies -- Testing a recursive (and possibly const) function expression

我正在将 Mocha 与 Sinon 结合使用并尝试测试递归调用 (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() 的东西,它似乎允许测试递归函数。

在我看来没有办法用诗乃来复制这种行为?我查看了以下错误报告/功能请求:

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

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

谢谢。

直接在函数上调用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);
  });
});

这种方法适用于非递归函数,但您可能会注意到,当第一个断言通过时,第二个断言失败,仅对 spy 进行了一次调用。

问题是这里还有一个问题。函数 fib 直接调用自身,并且不会通过用 sinon.spy.

包装函数来跟踪那些直接递归调用

.

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

将代码更改为 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);
  });
});

希望对您有所帮助。