同じオブジェクトをテストによってスパイ/スタブを切り替えて監視したい場合の書き方。
NGパターン
スパイ、スタブは共に対象オブジェクトをラップするものである。スパイとスタブが同じテスト内で同じオブジェクトをラップするのは、スパイを二重にラップするのと等しいため、エラーとなる。
import * as sinon from 'sinon';
class SinonResetMixed {
public methodToBeObserved(): void {
// do nothing
}
}
describe('Wraps same object by both spy and stub and uses simultaneously', () => {
let instance: SinonResetMixed;
let spy: sinon.SinonSpy;
let stub: sinon.SinonStub;
beforeAll(() => {
spy = sinon.spy(SinonResetMixed.prototype, 'methodToBeObserved');
stub = sinon.stub(SinonResetMixed.prototype, 'methodToBeObserved');
});
afterEach(() => {
sinon.restore();
});
it('cannot wrap same object by both spy and stub', () => {
instance = new SinonResetMixed();
instance.methodToBeObserved();
console.log(`Spy says methodToBeObserved has called ${spy.callCount} time(s)`);
console.log(`Stub says methodToBeObserved has called ${stub.callCount} time(s)`);
expect(spy.calledOnce).toBe(true);
expect(stub.calledOnce).toBe(true);
});
});
$ yarn test
FAIL src/SinonResetMixedNG.test.tsx
● Wraps same object by both spy and stub and uses simultaneously › cannot wrap same object by both spy and stub
TypeError: Attempted to wrap methodToBeObserved which is already wrapped
at checkWrappedMethod (node_modules/sinon/lib/sinon/util/core/wrap-method.js:38:21)
at wrapMethod (node_modules/sinon/lib/sinon/util/core/wrap-method.js:85:13)
at stub (node_modules/sinon/lib/sinon/stub.js:71:44)
at Sandbox.stub (node_modules/sinon/lib/sinon/sandbox.js:291:33)
at Object.<anonymous> (src/SinonResetMixedNG.test.tsx:15:18)
at new Promise (<anonymous>)
at Promise.resolve.then.el (node_modules/p-map/index.js:46:16)
at process._tickCallback (internal/process/next_tick.js:68:7)
--------------
Error: Stack Trace for original
at wrapMethod (node_modules/sinon/lib/sinon/util/core/wrap-method.js:110:31)
at Function.spy (node_modules/sinon/lib/sinon/spy.js:45:16)
at Sandbox.spy (node_modules/sinon/lib/sinon/sandbox.js:275:26)
at Object.<anonymous> (src/SinonResetMixedNG.test.tsx:14:17)
at new Promise (<anonymous>)
at Promise.resolve.then.el (node_modules/p-map/index.js:46:16)
at process._tickCallback (internal/process/next_tick.js:68:7)
● Wraps same object by both spy and stub and uses simultaneously › cannot wrap same object by both spy and stub
TypeError: Cannot read property 'callCount' of undefined
at Object.<anonymous> (src/SinonResetMixedNG.test.tsx:25:65)
at new Promise (<anonymous>)
at Promise.resolve.then.el (node_modules/p-map/index.js:46:16)
at process._tickCallback (internal/process/next_tick.js:68:7)
Wraps same object by both spy and stub and uses simultaneously
✕ cannot wrap same object by both spy and stub (1ms)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 total
Snapshots: 0 total
Time: 0.944s, estimated 1s
Ran all test suites matching /ng/.
console.log src/SinonResetMixedNG.test.tsx:26
Spy says methodToBeObserved has called 1 time(s)
OKパターン
対象となるオブジェクトが同じでも、スパイとスタブが同じテスト内に共存しなければOK。
import * as sinon from 'sinon';
class SinonResetMixed {
public methodToBeObserved(): void {
// do nothing
}
}
describe('Wraps same object by both spy and stub but uses separately', () => {
let instance: SinonResetMixed;
let spy: sinon.SinonSpy;
let stub: sinon.SinonStub;
afterEach(() => {
sinon.restore();
});
it('only uses spy', () => {
spy = sinon.spy(SinonResetMixed.prototype, 'methodToBeObserved');
instance = new SinonResetMixed();
instance.methodToBeObserved();
console.log(`Spy says methodToBeObserved has called ${spy.callCount} time(s)`);
expect(spy.calledOnce).toBe(true);
});
it('only uses stub', () => {
stub = sinon.stub(SinonResetMixed.prototype, 'methodToBeObserved');
instance = new SinonResetMixed();
instance.methodToBeObserved();
console.log(`Stub says methodToBeObserved has called ${stub.callCount} time(s)`);
expect(stub.calledOnce).toBe(true);
});
});
PASS src/SinonResetMixedOK.test.tsx
Wraps same object by both spy and stub but uses separately
✓ only uses spy (2ms)
✓ only uses stub (5ms)
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 1.031s
Ran all test suites matching /ok/.
console.log src/SinonResetMixedOK.test.tsx:23
Spy says methodToBeObserved has called 1 time(s)
console.log src/SinonResetMixedOK.test.tsx:30
Stub says methodToBeObserved has called 1 time(s)