Sinonエラーすでにラップされている関数をラップしようとしました


91

ここに同じ質問がありますが、私の問題に対する答えが見つからなかったので、ここに私の質問があります:

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

それぞれの説明で、しかしそれでも私に同じエラーを与えます。


回答:


113

getObjinafter()関数を復元する必要があります。以下のように試してください。

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

上記の受け入れられた方法を試した後、「何よりも」フックの下で同じエラーが発生します
Ashwin Hegde 2017

@AshwinHegde、テストコードを教えていただけませんか。多分私はここでいくつかの問題を見つけることができます。
zangw 2017

1
それぞれを指定せずにすべてのスタブを復元する方法はありませんか?sinon.restoreAll();スタブを復元することを忘れないようにするためだけに、すべてのテストの後に実行できるものがあると便利です。
ルーク

afterEach(()=> {sinon.verifyAndRestore();});
サムT

20

このエラーは、スタブ関数を適切に復元しないことが原因です。サンドボックスを使用してから、サンドボックスを使用してスタブを作成します。スイート内での各テストの後、サンドボックスを復元します

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

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

1
男、私の命を救った)
YegorZaremba19年

これは私のために働いた。これが受け入れられる答えだと思います。
ダニエルカプラン

ラッピング関数を使用した複数のテストがあり、afterEachを使用する必要があります。
リチャード

私の場合、これは正解でした。特定のメソッドではなくオブジェクト全体をスパイしていたため、復元できませんでした。
エジソンスペンサー

11

1つのオブジェクトのすべてのメソッドを復元する必要がある場合は、を使用できますsinon.restore(obj)

例:

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

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

1
オブジェクトの関数をスタブするとき、これは私にとってはうまくいきませんでした。受け入れられた回答が示すように、機能ごとに復元する必要がありました。
イアンロバートソン

7
sinon.restore()はSinon v2で非推奨になり、その後削除されました。 // Previously sinon.restore(stubObject); // Typescript (stubObject as any).restore(); // Javascript stubObject.restore();
MatthiasSommer

6

モカのbefore()フックとafter()フックを使ってこれを打っていました。どこでも述べたように、私もrestore()を使用していました。単一のテストファイルは正常に実行されましたが、複数は実行されませんでした。Mochaのルートレベルフックについて最終的に見つかりました:自分の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');
  });
});

3

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

3

サンドボックスを使用しても、エラーが発生する可能性があります。特に、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();
});

3

この問題が発生した場合、オブジェクト全体をスタブまたはスパイし、後で実行する場合

sandbox.restore()

それでもエラーが発生します。個々のメソッドをスタブ/スパイする必要があります。

私は何が悪いのかを理解しようとして永遠に無駄になりました。

シノン-7.5.0


2

私はスパイとこれに遭遇しました。この動作により、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);
};


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 }));
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.