【问题标题】:Sinon error Attempted to wrap function which is already wrappedSinon错误尝试包装已经包装的函数
【发布时间】:2016-07-04 15:10:26
【问题描述】:

虽然这里有同样的问题,但我找不到我的问题的答案,所以我的问题是:

我正在使用 mocha 和 chai 测试我的节点 js 应用程序。我正在使用 sinion 来包装我的函数。

describe('App Functions', function(){

  let mockObj = sinon.stub(testApp, 'getObj', (dbUrl) => {
     //some stuff
  });
  it('get results',function(done) {
     testApp.someFun
  });
}

describe('App Errors', function(){

  let mockObj = sinon.stub(testApp, 'getObj', (dbUrl) => {
     //some stuff
  });
  it('throws errors',function(done) {
     testApp.someFun
  });
}

当我尝试运行这个测试时,它给了我错误

Attempted to wrap getObj which is already wrapped

我也试过放

beforeEach(function () {
  sandbox = sinon.sandbox.create();
});

afterEach(function () {
  sandbox.restore();
});

在每个描述中,但仍然给我同样的错误。

【问题讨论】:

  • 你可以在帖子底部找到解释here

标签: node.js sinon


【解决方案1】:

你应该恢复after()函数中的getObj,请尝试如下。

describe('App Functions', function(){
    var mockObj;
    before(function () {
            mockObj = sinon.stub(testApp, 'getObj', () => {
                 console.log('this is sinon test 1111');
            });
    });

    after(function () {
        testApp.getObj.restore(); // Unwraps the spy
    });

    it('get results',function(done) {
        testApp.getObj();
    });
});

describe('App Errors', function(){
    var mockObj;
    before(function () {
            mockObj = sinon.stub(testApp, 'getObj', () => {
                 console.log('this is sinon test 1111');
            });
    });

    after( function () {
        testApp.getObj.restore(); // Unwraps the spy
    });

    it('throws errors',function(done) {
         testApp.getObj();
    });
});

【讨论】:

  • 在尝试了上述接受的方式后,我在“before all”钩子下遇到了同样的错误
  • @AshwinHegde,你能给我你的测试代码吗?也许我可以在这里找到一些问题。
  • 有没有办法在不指定每个存根的情况下恢复所有存根?有一个 sinon.restoreAll(); 可以在所有测试之后运行以确保您不会忘记恢复存根,这将是很棒的。
  • afterEach(()=> { sinon.verifyAndRestore(); });
【解决方案2】:

这个错误是由于没有正确恢复存根函数。使用沙箱,然后使用沙箱创建存根。在套件内的每次测试后,恢复沙盒

  beforeEach(() => {
      sandbox = sinon.createSandbox();
      mockObj = sandbox.stub(testApp, 'getObj', fake_function)
  });

  afterEach(() => {
      sandbox.restore();
  });

【讨论】:

  • 老兄,救了我的命)
  • 这对我有用。我觉得这应该是公认的答案。
  • 我有多个带有包装函数的测试,需要使用 afterEach
  • 就我而言,这是正确的答案,因为我正在监视整个对象而不是特定方法,因此无法恢复。
【解决方案3】:

如果需要恢复一个对象的所有方法,可以使用sinon.restore(obj)

示例:

before(() => {
    userRepositoryMock = sinon.stub(userRepository);
});

after(() => {
    sinon.restore(userRepository);
});

【讨论】:

  • 在对象上存根函数时,这对我不起作用。我必须像接受的答案所示那样恢复每个功能。
  • sinon.restore() 在 Sinon v2 中被弃用,之后被移除。 // Previously sinon.restore(stubObject); // Typescript (stubObject as any).restore(); // Javascript stubObject.restore();
【解决方案4】:

我也使用了 Mocha 的 before() 和 after() 钩子。我也在使用到处提到的 restore() 。单个测试文件运行良好,多个没有。 终于找到了关于Mocha root-level-hooks:我自己的describe()里面没有我的before()和after()。因此它会在根级别查找所有带有 before() 的文件,并在开始任何测试之前执行这些文件。

所以请确保您有类似的模式:

describe('my own describe', () => {
  before(() => {
    // setup stub code here
    sinon.stub(myObj, 'myFunc').callsFake(() => {
      return 'bla';
    });
  });
  after(() => {
    myObj.myFunc.restore();
  });
  it('Do some testing now', () => {
    expect(myObj.myFunc()).to.be.equal('bla');
  });
});

【讨论】:

    【解决方案5】:

    对于遇到此问题的任何人,如果您对整个对象进行存根或监视,并且您稍后会这样做

    沙盒.restore()

    您仍然会收到错误消息。您必须存根/监视各个方法。

    我一直在浪费时间试图找出问题所在。

    sinon-7.5.0

    【讨论】:

      【解决方案6】:

      建议在“beforeEach”中初始化存根并在“afterEach”中恢复它们。但如果您喜欢冒险,以下方法也可以。

      describe('App Functions', function(){
      
        let mockObj = sinon.stub(testApp, 'getObj', (dbUrl) => {
           //some stuff
        });
        it('get results',function(done) {
           testApp.someFun
           mockObj .restore();
        });
      }
      
      describe('App Errors', function(){
      
        let mockObj = sinon.stub(testApp, 'getObj', (dbUrl) => {
           //some stuff
        });
        it('throws errors',function(done) {
           testApp.someFun
           mockObj .restore();
        });
      }
      

      【讨论】:

        【解决方案7】:

        即使使用沙盒,它也可能会给您带来错误。尤其是在为 ES6 类并行运行测试时。

        const sb = sandbox.create();
        
        before(() => {
          sb.stub(MyObj.prototype, 'myFunc').callsFake(() => {
            return 'whatever';
          });
        });
        after(() => {
          sb.restore();
        });
        

        如果另一个测试试图从原型中存根 myFunc,这可能会引发相同的错误。 我能够解决这个问题,但我并不为此感到自豪......

        const sb = sandbox.create();
        
        before(() => {
          MyObj.prototype.myFunc = sb.stub().callsFake(() => {
            return 'whatever';
          });
        });
        after(() => {
          sb.restore();
        });
        

        【讨论】:

          【解决方案8】:

          我遇到了间谍。这种行为使 sinon 很难使用。我创建了一个辅助函数,它试图在设置新间谍之前删除任何现有的间谍。这样我就不必担心任何之前/之后的状态。类似的方法也可能适用于存根。

          import sinon, { SinonSpy } from 'sinon';
          
          /**
           * When you set a spy on a method that already had one set in a previous test,
           * sinon throws an "Attempted to wrap [function] which is already wrapped" error
           * rather than replacing the existing spy. This helper function does exactly that.
           *
           * @param {object} obj
           * @param {string} method
           */
          export const spy = function spy<T>(obj: T, method: keyof T): SinonSpy {
            // try to remove any existing spy in case it exists
            try {
              // @ts-ignore
              obj[method].restore();
            } catch (e) {
              // noop
            }
            return sinon.spy(obj, method);
          };

          【讨论】:

            【解决方案9】:

            只是提醒一下,因为我花了大约一个小时才弄清楚:

            如果您有两个(或更多)测试文件,并且发现自己仍然无论您尝试什么都会收到“已包装”错误,请确保您的 beforeEachafterEach 存根/替换处理程序位于测试文件的 describe 块内。

            如果你把它们放在全局测试范围内,即在describe('my test description', () =&gt; {}) 构造之外,sinon 会尝试两次并抛出这个。

            【讨论】:

            • 被严重低估的答案
            【解决方案10】:

            我遇到这种行为是因为该函数在其他地方被监视。因此,我删除了如下预定义的间谍并创建了自己的。

            obj.func.restore()
            let spy = sinon.spy(obj, 'func')
            

            有效。

            【讨论】:

              【解决方案11】:
              function stub(obj, method) {
                   // try to remove any existing stub in case it exists
                    try {
                      obj[method].restore();
                    } catch (e) {
                      // eat it.
                    }
                    return sinon.stub(obj, method);
                  }
              

              并在测试中创建存根时使用此函数。它将解决“Sinon error Attempted to wrap function which has been Wrapped”错误。

              示例:

              stub(Validator.prototype, 'canGeneratePayment').returns(Promise.resolve({ indent: dTruckIndent }));
              

              【讨论】:

                猜你喜欢
                • 2019-09-22
                • 2012-02-08
                • 1970-01-01
                • 1970-01-01
                • 2015-07-13
                • 2013-06-21
                • 1970-01-01
                • 1970-01-01
                • 2023-01-13
                相关资源
                最近更新 更多