Embora haja uma mesma pergunta aqui, mas eu não consegui encontrar uma resposta para o meu problema, então aqui vai minha pergunta:
Estou testando meu aplicativo node js usando mocha e chai. Estou usando o sinion para envolver minha função.
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
});
}
Quando tento executar este teste, ocorre um erro
Attempted to wrap getObj which is already wrapped
Eu também tentei colocar
beforeEach(function () {
sandbox = sinon.sandbox.create();
});
afterEach(function () {
sandbox.restore();
});
em cada descrição, mas ainda me dando o mesmo erro.
Respostas:
Você deve restaurar a função
getObj
inafter()
, tente como abaixo.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(); }); });
fonte
sinon.restoreAll();
que pudesse ser executado após todos os testes, apenas para garantir que você não se esqueça de restaurar um stub.Este erro é devido à não restauração da função stub corretamente. Use a caixa de areia e, a seguir, crie o esboço usando a caixa de areia. Após cada teste dentro do pacote, restaure o sandbox
beforeEach(() => { sandbox = sinon.createSandbox(); mockObj = sandbox.stub(testApp, 'getObj', fake_function) }); afterEach(() => { sandbox.restore(); });
fonte
Para os casos em que você precisa restaurar todos os métodos de um objeto, você pode usar o
sinon.restore(obj)
.Exemplo:
before(() => { userRepositoryMock = sinon.stub(userRepository); }); after(() => { sinon.restore(userRepository); });
fonte
// Previously sinon.restore(stubObject); // Typescript (stubObject as any).restore(); // Javascript stubObject.restore();
Eu também estava acertando isso usando os ganchos antes () e depois () do Mocha. Eu também estava usando restore () conforme mencionado em todos os lugares. Um único arquivo de teste funcionou bem, vários não. Finalmente descobri sobre ganchos de nível de raiz Mocha : Eu não tinha meu before () e after () dentro do meu describe (). Portanto, ele encontra todos os arquivos com before () no nível da raiz e os executa antes de iniciar qualquer teste.
Portanto, certifique-se de ter um padrão semelhante:
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'); }); });
fonte
É aconselhável inicializar os stubs em 'beforeEach' e restaurá-los em 'afterEach'. Mas caso você esteja se sentindo aventureiro, o seguinte também 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(); }); }
fonte
Mesmo com o sandbox, ele pode dar o erro. Especialmente quando os testes são executados em paralelo para as classes ES6.
const sb = sandbox.create(); before(() => { sb.stub(MyObj.prototype, 'myFunc').callsFake(() => { return 'whatever'; }); }); after(() => { sb.restore(); });
isso pode gerar o mesmo erro se outro teste estiver tentando stub myFunc do Prototype. Consegui consertar isso, mas não tenho orgulho disso ...
const sb = sandbox.create(); before(() => { MyObj.prototype.myFunc = sb.stub().callsFake(() => { return 'whatever'; }); }); after(() => { sb.restore(); });
fonte
Para qualquer pessoa com esse problema, se você fizer stub ou espionar o objeto inteiro, e mais tarde fizer
Você ainda receberá o erro. Você tem que stub / espiar os métodos individuais.
Eu perdi uma eternidade tentando descobrir o que estava errado.
sinon-7.5.0
fonte
Eu corri para isso com espiões. Esse comportamento torna o sinon bastante inflexível para trabalhar. Eu criei uma função auxiliar que tenta remover qualquer espião existente antes de definir um novo. Dessa forma, não preciso me preocupar com nenhum estado de antes / depois. Uma abordagem semelhante também pode funcionar para 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); };
fonte
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); }
e use esta função ao criar stubs em testes. Ele resolverá o erro 'Erro de Sinon Tentativa de função de agrupamento que já está agrupado'.
exemplo:
stub(Validator.prototype, 'canGeneratePayment').returns(Promise.resolve({ indent: dTruckIndent }));
fonte