【问题标题】:Sinon Spies -- Testing a recursive (and possibly const) function expressionSinon Spies -- 测试递归(也可能是 const)函数表达式
【发布时间】:2018-08-05 17:22:37
【问题描述】:

我正在将 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

谢谢。

【问题讨论】:

    标签: javascript mocha.js sinon


    【解决方案1】:

    直接在函数上调用 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 包装函数来跟踪。

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

    【讨论】:

    • 感谢您的回复!我是否理解测试递归函数的唯一方法是重写它,以便它调用包装器对象?这对我来说似乎是一种不可接受的做法,因为我的代码可能会与我在测试中重新编写的代码有所不同。我正在尝试记忆 fib,但是,我想通过应用函数包装器来记忆它。 Jasmine 有一个叫做 .callThrough() 的东西,诗乃没有?
    • @DanielLynch 这是一个不断以不同方式被问到的问题(不同的细节,例如哪个测试框架等),所以我创建了一个新的问题/答案,详细解释了这个问题并提出了相应的解决方案。我在上面编辑了我的答案以链接到该答案。让我知道它是否满足您的需求。
    【解决方案2】:

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

    希望对你有帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-03-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多