Sinon-Fehler Es wurde versucht, die bereits umschlossene Funktion zu umbrechen

88

Es gibt hier zwar die gleiche Frage, aber ich konnte keine Antwort auf mein Problem finden. Hier ist meine Frage:

Ich teste meine Node JS App mit Mokka und Chai. Ich benutze Sinion, um meine Funktion zu verpacken.

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

Wenn ich versuche, diesen Test auszuführen, wird mir ein Fehler angezeigt

Attempted to wrap getObj which is already wrapped

Ich habe auch versucht zu setzen

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

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

in jedem beschreiben, aber immer noch den gleichen Fehler geben.

Rohit Vyavahare
quelle
Eine Erklärung finden Sie am Ende des Beitrags hier
Nir Alfasi

Antworten:

108

Sie sollten die getObjIn- after()Funktion wiederherstellen . Bitte versuchen Sie es wie folgt.

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();
    });
});
zangw
quelle
Nachdem ich den oben akzeptierten Weg ausprobiert habe, erhalte ich den gleichen Fehler unter "vor allem"
Ashwin Hegde
@AshwinHegde, können Sie mir bitte Ihre Testcodes geben? Vielleicht kann ich hier ein Problem finden.
Zangw
1
Gibt es keine Möglichkeit, alle Stubs wiederherzustellen, ohne jeden anzugeben? Es wäre großartig, eine zu haben sinon.restoreAll();, die nach allen Tests ausgeführt werden könnte, nur um sicherzustellen, dass Sie nicht vergessen, einen Stub wiederherzustellen.
Luke
20

Dieser Fehler ist darauf zurückzuführen, dass die Stub-Funktion nicht ordnungsgemäß wiederhergestellt wurde. Verwenden Sie die Sandbox und erstellen Sie den Stub mithilfe der Sandbox. Stellen Sie nach jedem Test in der Suite die Sandbox wieder her

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

  afterEach(() => {
      sandbox.restore();
  });
Arjun Malik
quelle
1
Alter, hat mein Leben gerettet)
Yegor Zaremba
Das hat bei mir funktioniert. Ich denke, dies sollte die akzeptierte Antwort sein.
Daniel Kaplan
Ich hatte mehrere Tests mit Wrapping-Funktionen und muss afterEach verwenden .
Richard
In meinem Fall war dies die richtige Antwort, da ich ein ganzes Objekt und keine bestimmte Methode ausspioniert habe und daher nicht wiederherstellen konnte.
Edison Spencer
11

In Fällen, in denen Sie alle Methoden eines Objekts wiederherstellen müssen, können Sie die verwenden sinon.restore(obj).

Beispiel:

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

after(() => {
    sinon.restore(userRepository);
});
Renan Ferreira
quelle
1
Dies hat bei mir beim Stubben von Funktionen für das Objekt nicht funktioniert. Ich musste pro Funktion wiederherstellen, wie die akzeptierte Antwort zeigt.
Ian Robertson
7
sinon.restore () wurde in Sinon v2 nicht mehr unterstützt und anschließend entfernt. // Previously sinon.restore(stubObject); // Typescript (stubObject as any).restore(); // Javascript stubObject.restore();
MatthiasSommer
6

Ich habe dies auch mit den before () und after () Hooks von Mocha getroffen. Ich habe auch das restore () verwendet, wie überall erwähnt. Eine einzelne Testdatei lief einwandfrei, mehrere nicht. Endlich über Mokka Root-Level-Hooks gefunden : Ich hatte mein Vorher () und Nachher () nicht in meinem eigenen beschreiben (). Es findet also alle Dateien mit before () auf Stammebene und führt diese aus, bevor Tests gestartet werden.

Stellen Sie also sicher, dass Sie ein ähnliches Muster haben:

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');
  });
});
Wilfred Dittmer
quelle
3

Es wird empfohlen, Stubs in 'beforeEach' zu initialisieren und in 'afterEach' wiederherzustellen. Wenn Sie sich jedoch abenteuerlustig fühlen, funktioniert auch Folgendes.

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

Selbst mit Sandbox könnte es Ihnen den Fehler geben. Insbesondere, wenn Tests für ES6-Klassen parallel ausgeführt werden.

const sb = sandbox.create();

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

Dies könnte den gleichen Fehler auslösen, wenn ein anderer Test versucht, myFunc vom Prototyp zu entfernen. Ich konnte das beheben, bin aber nicht stolz darauf ...

const sb = sandbox.create();

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

Für alle, die auf dieses Problem stoßen, wenn Sie das gesamte Objekt stummeln oder ausspionieren und dies später tun

sandbox.restore ()

Sie werden immer noch den Fehler erhalten. Sie müssen die einzelnen Methoden stub / spy.

Ich habe für immer versucht herauszufinden, was los war.

sinon-7.5.0

Khon Lieu
quelle
1

Ich bin mit Spionen darauf gestoßen. Dieses Verhalten macht es ziemlich unflexibel, mit Sinon zu arbeiten. Ich habe eine Hilfsfunktion erstellt, die versucht, vorhandene Spione zu entfernen, bevor neue festgelegt werden. Auf diese Weise muss ich mir keine Sorgen um einen Vorher / Nachher-Zustand machen. Ein ähnlicher Ansatz könnte auch für Stubs funktionieren.

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

Phil
quelle