试图包装已经包装的函数

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

我正在测试我的节点 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();
});

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

98017 次浏览

您应该恢复 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();
});
});

更新2022/01/22

使用 Sinon 的 Sanbox,您可以创建与 sandbox.stub()的存根模拟和恢复所有通过 sandbox.restore()创建的假货,阿尔琼马利克给出了一个良好的 例子

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

例如:

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


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

我还使用了 Mocha 的 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');
});
});

我们建议在‘ before each’中初始化存根,并在‘ after each’中恢复它们。但是如果你想要冒险的话,下面的方法也可以。

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();
});
}

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

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


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

即使使用沙箱,它也会给出错误,特别是当并行运行 ES6类的测试时。

const sb = sandbox.create();


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

如果另一个测试试图从 Prototype 中删除 myFunc,这可能会抛出相同的错误。 我能修好它,但我并不以此为荣。

const sb = sandbox.create();


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

我遇到了间谍。这种行为使得 sinon 的工作相当不灵活。我创建了一个 helper 函数,它试图在设置一个新的间谍之前删除任何现有的间谍。这样我就不用担心之前和之后的状态了。类似的方法可能也适用于存根。

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);
};

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

Sandbox.return ()

你仍然会得到错误。你必须存根/间谍的个别方法。

我浪费了那么多时间想弄清楚到底是怎么回事。

Sinon-7.5.0

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 错误试图包装已经包装的函数”错误。

例如:

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

提醒你一下,我花了一个小时才想明白:

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

如果您将它们放在全局测试范围中,即在 describe('my test description', () => {})构造之外,sinon 将尝试两次并抛出此操作。

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

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

有用。