Sinon error Intento de envolver la función que ya está envuelta

92

Aunque hay una misma pregunta aquí, pero no pude encontrar la respuesta a mi problema, aquí va mi pregunta:

Estoy probando mi aplicación node js usando mocha y chai. Estoy usando sinion para envolver mi función.

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

Cuando intento ejecutar esta prueba, me da un error

Attempted to wrap getObj which is already wrapped

También intenté poner

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

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

en cada descripción, pero todavía me da el mismo error.

Rohit Vyavahare
fuente
Puede encontrar una explicación al final de la publicación aquí
Nir Alfasi

Respuestas:

113

Debe restaurar la función getObjin after(), inténtelo de la siguiente manera.

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
fuente
Después de intentar la forma aceptada anteriormente, obtengo el mismo error en el gancho "antes de todo"
Ashwin Hegde
@AshwinHegde, ¿podría darme sus códigos de prueba? Quizás pueda encontrar algún problema aquí.
zangw
1
¿No hay forma de restaurar todos los stubs sin especificar cada uno? Sería genial tener un sinon.restoreAll();archivo que pudiera ejecutarse después de todas las pruebas solo para asegurarse de que no se olvide de restaurar un código auxiliar.
Lucas
afterEach (() => {sinon.verifyAndRestore ();});
Sam T
20

Este error se debe a que no se ha restaurado correctamente la función stub. Use sandbox y luego cree el stub usando sandbox. Después de cada prueba dentro de la suite, restaure la caja de arena

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

  afterEach(() => {
      sandbox.restore();
  });
Arjun Malik
fuente
1
amigo, me salvó la vida)
Yegor Zaremba
Esto funcionó para mí. Siento que esta debería ser la respuesta aceptada.
Daniel Kaplan
Tuve varias pruebas con funciones de envoltura y necesito usar afterEach .
Richard
En mi caso, esta fue la respuesta correcta, ya que estaba espiando un objeto completo y no un método específico, por lo que no pude restaurar.
Edison Spencer
11

Para los casos en los que necesite restaurar todos los métodos de un objeto, puede usar la extensión sinon.restore(obj).

Ejemplo:

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

after(() => {
    sinon.restore(userRepository);
});
Renan Ferreira
fuente
1
Esto no funcionó para mí cuando stubing funciones en el objeto. Tuve que restaurar por función como muestra la respuesta aceptada.
Ian Robertson
7
sinon.restore () quedó obsoleto en Sinon v2 y se eliminó posteriormente. // Previously sinon.restore(stubObject); // Typescript (stubObject as any).restore(); // Javascript stubObject.restore();
MatthiasSommer
6

También estaba golpeando esto usando los ganchos antes () y después () de Mocha. También estaba usando restore () como se menciona en todas partes. Un solo archivo de prueba funcionó bien, varios no. Finalmente encontré sobre los ganchos de nivel de raíz de Mocha : no tenía mi antes () y después () dentro de mi propio describe (). Por lo tanto, encuentra todos los archivos con before () en el nivel raíz y los ejecuta antes de iniciar cualquier prueba.

Así que asegúrese de tener un patrón similar:

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
fuente
3

Se recomienda inicializar los stubs en 'beforeEach' y restaurarlos en 'afterEach'. Pero en caso de que se sienta aventurero, lo siguiente también funciona.

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
fuente
3

Incluso con sandbox podría darte el error. Especialmente cuando las pruebas se ejecutan en paralelo para las clases de ES6.

const sb = sandbox.create();

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

esto podría arrojar el mismo error si otra prueba intenta eliminar myFunc del Prototype. Pude arreglar eso pero no estoy orgulloso de eso ...

const sb = sandbox.create();

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

Para cualquiera que se encuentre con este problema, si detecta o espía todo el objeto, y luego lo hace

sandbox.restore ()

Seguirá recibiendo el error. Tienes que eliminar / espiar los métodos individuales.

Perdí para siempre tratando de averiguar qué estaba mal.

sinon-7.5.0

Khon Lieu
fuente
2

Me encontré con esto con espías. Este comportamiento hace que sinon sea bastante inflexible para trabajar. Creé una función de ayuda que intenta eliminar cualquier espía existente antes de configurar uno nuevo. De esa manera no tengo que preocuparme por ningún estado antes / después. Un enfoque similar también podría funcionar para los talones.

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

y use esta función cuando cree stubs en pruebas. Resolverá el error 'Sinon error Intento de envolver la función que ya está envuelta'.

ejemplo:

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