Erreur Sinon Tentative de bouclage de la fonction déjà encapsulée

92

Bien qu'il y ait une même question ici mais je n'ai pas trouvé de réponse à mon problème, voici ma question:

Je teste mon application node js en utilisant mocha et chai. J'utilise sinion pour envelopper ma fonction.

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

Quand j'essaye d'exécuter ce test, cela me donne une erreur

Attempted to wrap getObj which is already wrapped

J'ai aussi essayé de mettre

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

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

dans chaque décrire, mais me donnant toujours la même erreur.

Rohit Vyavahare
la source
Vous pouvez trouver une explication au bas de l'article ici
Nir Alfasi

Réponses:

113

Vous devez restaurer la fonction getObjin after(), veuillez l'essayer comme ci-dessous.

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
la source
Après avoir essayé la méthode acceptée ci-dessus, j'obtiens la même erreur sous le crochet "avant tout"
Ashwin Hegde
@AshwinHegde, pouvez-vous me donner vos codes de test? Peut-être que je peux trouver un problème ici.
zangw
1
N'existe-t-il aucun moyen de restaurer tous les stubs sans spécifier chacun d'eux? Ce serait génial d'avoir un sinon.restoreAll();qui pourrait être exécuté après tous les tests juste pour vous assurer de ne pas oublier de restaurer un stub.
Luke
afterEach (() => {sinon.verifyAndRestore ();});
Sam T
20

Cette erreur est due à une mauvaise restauration de la fonction de stub. Utilisez sandbox, puis créez le stub à l'aide du sandbox. Après chaque test dans la suite, restaurez le bac à sable

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

  afterEach(() => {
      sandbox.restore();
  });
Arjun Malik
la source
1
mec, m'a sauvé la vie)
Yegor Zaremba
Cela a fonctionné pour moi. Je pense que cela devrait être la réponse acceptée.
Daniel Kaplan
J'ai eu plusieurs tests avec des fonctions d'emballage et j'ai besoin d'utiliser afterEach .
Richard
Dans mon cas, c'était la bonne réponse, puisque j'espionnais un objet entier et non une méthode spécifique, donc je ne pouvais pas restaurer.
Edison Spencer
11

Pour les cas où vous devez restaurer toutes les méthodes d'un objet, vous pouvez utiliser le sinon.restore(obj).

Exemple:

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

after(() => {
    sinon.restore(userRepository);
});
Renan Ferreira
la source
1
Cela n'a pas fonctionné pour moi lors de la suppression de fonctions sur l'objet. J'ai dû restaurer par fonction comme le montre la réponse acceptée.
Ian Robertson
7
sinon.restore () était obsolète dans Sinon v2 et supprimée par la suite. // Previously sinon.restore(stubObject); // Typescript (stubObject as any).restore(); // Javascript stubObject.restore();
MatthiasSommer
6

J'étais également en train de le frapper en utilisant les crochets before () et after () de Mocha. J'utilisais également la restauration () comme mentionné partout. Un seul fichier de test a bien fonctionné, pas plusieurs. Finalement trouvé à propos des hooks de niveau racine Mocha : je n'avais pas mon avant () et après () dans mon propre describe (). Il trouve donc tous les fichiers avec before () au niveau racine et les exécute avant de commencer les tests.

Assurez-vous donc que vous avez un modèle similaire:

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
la source
3

Il est conseillé d'initialiser les stubs dans 'beforeEach' et de les restaurer dans 'afterEach'. Mais si vous vous sentez aventureux, ce qui suit fonctionne aussi.

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
la source
3

Même avec sandbox, cela pourrait vous donner l'erreur. Surtout lorsque les tests sont exécutés en parallèle pour les classes ES6.

const sb = sandbox.create();

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

cela pourrait générer la même erreur si un autre test tente de stuber myFunc du Prototype. J'ai pu résoudre ce problème mais je n'en suis pas fier ...

const sb = sandbox.create();

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

Pour toute personne rencontrant ce problème, si vous stub ou espionnez l'objet entier, et que vous le faites plus tard

sandbox.restore ()

Vous obtiendrez toujours l'erreur. Vous devez stub / espionner les méthodes individuelles.

J'ai perdu une éternité à essayer de comprendre ce qui n'allait pas.

sinon-7.5.0

Khon Lieu
la source
2

J'ai rencontré ça avec des espions. Ce comportement rend sinon assez rigide à travailler. J'ai créé une fonction d'assistance qui tente de supprimer tout espion existant avant d'en définir un nouveau. De cette façon, je n'ai pas à m'inquiéter de l'état avant / après. Une approche similaire pourrait également fonctionner pour les stubs.

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

et utilisez cette fonction lors de la création de stubs dans les tests. Cela résoudra l'erreur «Sinon erreur Tentative de boucler la fonction qui est déjà encapsulée».

exemple:

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