Chociaż jest tutaj to samo pytanie, ale nie mogłem znaleźć odpowiedzi na mój problem, oto moje pytanie:
Testuję moją aplikację node js przy użyciu mocha i chai. Używam sinion do zawijania mojej funkcji.
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
});
}
Kiedy próbuję uruchomić ten test, wyświetla mi się błąd
Attempted to wrap getObj which is already wrapped
Próbowałem też umieścić
beforeEach(function () {
sandbox = sinon.sandbox.create();
});
afterEach(function () {
sandbox.restore();
});
w każdym opisie, ale nadal daje mi ten sam błąd.
Odpowiedzi:
Powinieneś przywrócić funkcję
getObj
inafter()
, wypróbuj ją jak poniżej.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(); }); });
źródło
sinon.restoreAll();
który można uruchomić po wszystkich testach, aby upewnić się, że nie zapomnisz przywrócić kodu pośredniczącego.Ten błąd jest spowodowany nieprawidłowym przywróceniem funkcji kodu pośredniczącego. Użyj piaskownicy, a następnie utwórz kod pośredniczący za pomocą piaskownicy. Po każdym teście w pakiecie przywróć piaskownicę
beforeEach(() => { sandbox = sinon.createSandbox(); mockObj = sandbox.stub(testApp, 'getObj', fake_function) }); afterEach(() => { sandbox.restore(); });
źródło
W przypadkach, w których musisz przywrócić wszystkie metody jednego obiektu, możesz użyć
sinon.restore(obj)
.Przykład:
before(() => { userRepositoryMock = sinon.stub(userRepository); }); after(() => { sinon.restore(userRepository); });
źródło
// Previously sinon.restore(stubObject); // Typescript (stubObject as any).restore(); // Javascript stubObject.restore();
Uderzałem w to również za pomocą haków przed () i after () w Mocha. Używałem również funkcji restore (), jak wspomniano wszędzie. Pojedynczy plik testowy działał poprawnie, wiele nie. Wreszcie znalazłem informacje o hakach poziomu głównego Mocha : nie miałem moich przed () i after () w moim własnym opisie (). Znajduje więc wszystkie pliki z przed () na poziomie głównym i wykonuje je przed rozpoczęciem jakichkolwiek testów.
Więc upewnij się, że masz podobny wzór:
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'); }); });
źródło
Zaleca się zainicjowanie kodów pośredniczących w „beforeEach” i przywrócenie ich w „afterEach”. Ale jeśli masz ochotę na przygodę, działa również poniższe rozwiązanie.
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(); }); }
źródło
Nawet z piaskownicą może to spowodować błąd. Zwłaszcza, gdy testy są wykonywane równolegle dla klas ES6.
const sb = sandbox.create(); before(() => { sb.stub(MyObj.prototype, 'myFunc').callsFake(() => { return 'whatever'; }); }); after(() => { sb.restore(); });
może to spowodować ten sam błąd, jeśli inny test próbuje odgiąć myFunc z prototypu. Udało mi się to naprawić, ale nie jestem z tego dumny ...
const sb = sandbox.create(); before(() => { MyObj.prototype.myFunc = sb.stub().callsFake(() => { return 'whatever'; }); }); after(() => { sb.restore(); });
źródło
Dla każdego, kto napotka ten problem, jeśli zablokujesz lub szpiegujesz cały obiekt, a później to zrobisz
Nadal będziesz otrzymywać błąd. Musisz zablokować / szpiegować poszczególne metody.
Straciłem wieczność próbując dowiedzieć się, co było nie tak.
sinon-7.5.0
źródło
Wpadłem na to ze szpiegami. Takie zachowanie sprawia, że praca z sinonem jest dość nieelastyczna. Stworzyłem funkcję pomocniczą, która próbuje usunąć istniejącego szpiega przed ustawieniem nowego. W ten sposób nie muszę się martwić o stan przed / po. Podobne podejście może działać również w przypadku kodów pośredniczących.
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); };
źródło
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); }
i użyj tej funkcji podczas tworzenia kodów pośredniczących w testach. To rozwiąże błąd „Sinon error Próbowano opakować funkcję, która jest już opakowana”.
przykład:
stub(Validator.prototype, 'canGeneratePayment').returns(Promise.resolve({ indent: dTruckIndent }));
źródło