Lỗi Sinon Đã cố gắng bọc chức năng đã được bọc


91

Mặc dù có cùng một câu hỏi ở đây nhưng tôi không thể tìm thấy câu trả lời cho vấn đề của mình vì vậy đây là câu hỏi của tôi:

Tôi đang thử nghiệm ứng dụng node js của mình bằng mocha và chai. Tôi đang sử dụng sinion để bọc chức năng của mình.

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

Khi tôi cố gắng chạy thử nghiệm này, nó báo cho tôi lỗi

Attempted to wrap getObj which is already wrapped

Tôi cũng đã thử đặt

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

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

trong mỗi mô tả, nhưng vẫn cho tôi cùng một lỗi.


Bạn có thể tìm thấy một lời giải thích ở dưới cùng của bài viết ở đây
Nir Alfasi

Câu trả lời:


113

Bạn nên khôi phục chức năng getObjtrong after(), vui lòng thử nó như bên dưới.

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

Sau khi thử các cách được chấp nhận ở trên, tôi nhận được lỗi tương tự dưới "trước khi tất cả" móc
Ashwin Hegde

@AshwinHegde, bạn có thể cho tôi xin mã kiểm tra được không? Có lẽ tôi có thể tìm thấy một số vấn đề ở đây.
zangw

1
Không có cách nào để khôi phục tất cả các sơ khai mà không chỉ định từng cái? Sẽ thật tuyệt nếu có một chương trình sinon.restoreAll();có thể chạy sau tất cả các thử nghiệm chỉ để đảm bảo rằng bạn không quên khôi phục sơ khai.
Luke

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

20

Lỗi này là do không khôi phục đúng chức năng sơ khai. Sử dụng hộp cát và sau đó tạo sơ khai bằng hộp cát. Sau mỗi lần kiểm tra bên trong bộ, hãy khôi phục hộp cát

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

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

1
anh bạn, đã cứu mạng tôi)
Yegor Zaremba

Điều này đã làm việc cho tôi. Tôi cảm thấy đây phải là câu trả lời được chấp nhận.
Daniel Kaplan

Tôi đã có nhiều thử nghiệm với các hàm gói và cần sử dụng afterEach .
Richard

Trong trường hợp của tôi, đây là câu trả lời chính xác, vì tôi đang theo dõi toàn bộ đối tượng chứ không phải một phương pháp cụ thể, vì vậy tôi không thể khôi phục.
Edison Spencer

11

Đối với trường hợp bạn cần khôi phục tất cả các phương thức của một đối tượng, bạn có thể sử dụng sinon.restore(obj).

Thí dụ:

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

after(() => {
    sinon.restore(userRepository);
});

1
Điều này không hoạt động đối với tôi khi khai thác các hàm trên đối tượng. Tôi đã phải khôi phục mỗi chức năng như các chương trình trả lời được chấp nhận.
Ian Robertson

7
sinon.restore () không được chấp nhận trong Sinon v2 và bị xóa sau đó. // Previously sinon.restore(stubObject); // Typescript (stubObject as any).restore(); // Javascript stubObject.restore();
MatthiasSommer

6

Tôi cũng đã đánh điều này bằng cách sử dụng hook before () và after () của Mocha. Tôi cũng đang sử dụng khôi phục () như đã đề cập ở khắp mọi nơi. Một tệp kiểm tra chạy tốt, nhiều tệp thì không. Cuối cùng đã tìm thấy về Mocha root-level-hooks : Tôi không có before () và after () bên trong mô tả () của riêng tôi. Vì vậy, nó tìm tất cả các tệp có before () ở cấp cơ sở và thực thi chúng trước khi bắt đầu bất kỳ thử nghiệm nào.

Vì vậy, hãy đảm bảo rằng bạn có một mẫu tương tự:

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

Bạn nên khởi tạo các sơ khai trong 'beforeEach' và khôi phục chúng trong 'afterEach'. Nhưng trong trường hợp bạn đang cảm thấy mạo hiểm, những điều sau đây cũng rất hiệu quả.

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

Ngay cả với hộp cát, nó có thể cung cấp cho bạn lỗi. Đặc biệt là khi các bài kiểm tra chạy song song cho các lớp ES6.

const sb = sandbox.create();

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

điều này có thể gây ra cùng một lỗi nếu một thử nghiệm khác đang cố gắng khai thác myFunc khỏi Nguyên mẫu. Tôi đã có thể sửa chữa điều đó nhưng tôi không tự hào về nó ...

const sb = sandbox.create();

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

3

Đối với bất kỳ ai gặp phải vấn đề này, nếu bạn khai báo hoặc theo dõi toàn bộ đối tượng và sau đó bạn làm

sandbox.restore ()

Bạn vẫn sẽ gặp lỗi. Bạn phải khai / theo dõi các phương pháp riêng lẻ.

Tôi đã lãng phí mãi mãi khi cố gắng tìm ra điều gì sai.

sinon-7.5.0


2

Tôi đã gặp phải điều này với gián điệp. Hành vi này làm cho sinon khá không linh hoạt để làm việc với. Tôi đã tạo một chức năng trợ giúp cố gắng loại bỏ bất kỳ gián điệp hiện có nào trước khi thiết lập một gián điệp mới. Bằng cách đó tôi không phải lo lắng về bất kỳ trạng thái trước / sau. Một cách tiếp cận tương tự cũng có thể hiệu quả đối với các bài sơ khai

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

và sử dụng chức năng này khi tạo sơ khai trong các bài kiểm tra. Nó sẽ giải quyết lỗi 'Sinon error Đã cố gắng bọc chức năng đã được bọc'.

thí dụ:

stub(Validator.prototype, 'canGeneratePayment').returns(Promise.resolve({ indent: dTruckIndent }));
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.