Помилка Sinon. Спроба обернути функцію, яка вже обернута


92

Хоча тут є те саме питання, але я не зміг знайти відповідь на свою проблему, тому тут йде моє запитання:

Я тестую свою програму node 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

Вам слід відновити функцію getObjin after(), спробуйте, як показано нижче.

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

Спробувавши вищевказаний спосіб, я отримую ту саму помилку під заголовком "до всіх"
Ашвін Хегде,

@AshwinHegde, не могли б ви дати мені свої тестові коди? Можливо, я можу знайти тут якусь проблему.
zangw

1
Чи неможливо відновити всі заглушки, не вказавши кожен з них? Було б чудово мати такий, sinon.restoreAll();який можна було б запускати після всіх тестів, лише щоб переконатись, що ви не забули відновити заглушку.
Лука

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

20

Ця помилка пов’язана з неправильним відновленням функції заглушки. Використовуйте пісочницю, а потім створіть заглушку за допомогою пісочниці. Після кожного тесту всередині набору відновіть пісочницю

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

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

1
чувак, врятував мені життя)
Єгор Заремба

Це спрацювало для мене. Я вважаю, що це має бути прийнятою відповіддю.
Даніель Каплан

Я провів кілька тестів із функціями обтікання, і їх потрібно було використовувати після кожного .
Річард

У моєму випадку це була правильна відповідь, оскільки я шпигував цілим об’єктом, а не конкретним методом, тому не міг відновити.
Едісон Спенсер,

11

У випадках, коли вам потрібно відновити всі методи одного об'єкта, ви можете використовувати файл 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();
Маттіас

6

Я також вдарив про це за допомогою крючків Mocha до () та після (). Я також використовував функцію відновлення (), про яку згадували всюди. Один тестовий файл працював нормально, кілька - ні. Нарешті знайшов про хуки кореневого рівня Mocha : у мене не було моїх до () та після () всередині мого власного опису (). Тому він знаходить усі файли з 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

Я зіткнувся з цим зі шпигунами. Така поведінка робить синона досить негнучким для роботи. Я створив допоміжну функцію, яка намагається видалити будь-якого існуючого шпигуна перед тим, як встановити нового. Таким чином, мені не доведеться турбуватися про будь-який стан до / після. Подібний підхід може працювати і для заглушок.

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 }));
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.