sinon.stub
/ sandbox.stub
์(๋) ์ฃผ๋ฐฉ ์ฑํฌ๋๊ฐ ๋์์ต๋๋ค.
ํ๊ท ์์ด๋ ์ฐพ์ ์์ ํ๊ธฐ ์ด๋ ค์ด ๋ฌธ์ ๊ฐ ์๋ ๊ตฌ์ฑ ๊ฐ๋ฅํ ๋์์
๋๋ค.
๊ทธ ์ด๋ ค์์ ๊ทผ๋ณธ ์์ธ์ stub
์ ์ฑ
์์ด ๋๋ฌด ๋ง๊ธฐ ๋๋ฌธ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค.
๋ํ stub
๋ ๋์์ด ์์ฑ๋ ํ์ ์ค์ ๋๊ณ ์ฌ๋ฌ ๋ฒ ์ฌ์ ์๋ ์ ์๋ค๋ ์ฌ์ค๋ก ์ธํด ์ฌ์ฉ์ ๋ฌธ์ ๊ฐ ์์ต๋๋ค.
var myStub;
beforeEach(function(){
myStub = sinon.stub().resolves('apple pie :)');
});
// several hundred lines of tests later
myStub = sinon.stub().rejects('no more pie :(');
// several hundred lines of tests later
// what behaviour does myStub currently have? Can you tell without
// reading the entire file?
// can you safely change the behaviour without affecting tests further
// down in the file?
๊ทธ๋ฆฌ๊ณ ๋ ํผ๋์ค๋ฌ์ด ์๋๋ฆฌ์ค๊ฐ ์์ต๋๋ค.
var myStub = sinon.stub()
.withArgs(42)
.onThirdCall()
.resolves('apple pie')
.rejects('no more pie')
๊ทธ๊ฒ์ ๋ฌด์์ํฉ๋๊น?
stub
์ ๊ณ์ํด์ ๋ ๋ง์ ์ฑ
์์ ์ถ๊ฐํ๋ ๋์ ๋ฒ์๊ฐ ํจ์ฌ ์ข์ sinon
์ ์ ๊ตฌ์ฑ์์ ์๊ฐํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
๋ด๊ฐ ์๊ฐํ ์ ์๋ ๊ฐ์ฅ ์ค์ํ ๊ฒ์ ํจ์์ ๋ํ ๋ถ๋ณ์ ๋์ ์ผ ๊ฒ์ ๋๋ค.
๊ทธ๋ฐ ๋ค์ ๋์ค์ ์์ฑ์ ๋ํด ์ํํ ์์ ์ ํ์ ํ ์ ์์ต๋๋ค(๋ณ๋์ ์ ๋จ์ผ ์ฑ ์ ๊ตฌ์ฑ์).
sinon.fake
fake
( sinon.fake
ํธ์ถ์ ๋ฐํ ๊ฐ)์ ์์ ํ๊ณ ๋ณ๊ฒฝํ ์ ์๋ Function
์
๋๋ค. ๊ทธ๊ฒ์ ํ ๊ฐ์ง ์ผ๋ง ํฉ๋๋ค. ๋ชจ๋ ํธ์ถ์์ ๋์ผํ ๋์์ ํฉ๋๋ค . stub
์ ๋ฌ๋ฆฌ ๋์์ ์ฌ์ ์ํ ์ ์์ต๋๋ค. ๋ค๋ฅธ ๋์์ด ํ์ํ๋ฉด fake
๋ฅผ ์๋ก ๋ง๋์ญ์์ค.
๊ฐ์ง๋ ์ด๋ฌํ ์ฑ ์ ์ค ํ๋ ๋ฅผ ๊ฐ์ง ์ ์์ต๋๋ค.
Promise
๋ฅผ ๊ฐ์ผ๋ก ํด์Promise
์ Error
๋ก ๊ฑฐ๋ถError
๋์ง๋ค๋ถ์์ฉ์ ์ํ๊ฑฐ๋ ํ์ํ๊ณ ์ฌ์ ํ ์คํ์ด ์ธํฐํ์ด์ค๋ฅผ ์ํ๋ค๋ฉด ์ค์ ํจ์๋ฅผ ์ฌ์ฉํ๊ฑฐ๋ stub
๋ฅผ ์ฌ์ฉํ๊ฑฐ๋ ์ฌ์ฉ์ ์ ์ ํจ์๋ฅผ ๋ง๋์ญ์์ค.
sinon.replace(myObject, myMethod, sandbox.spy(function(args) {
someFunctionWithSideEffects(args);
});
์ฌ์ฉ์๊ฐ ์ง์๋์ง ์๋ ๋ฐฉ์์ผ๋ก ์ค๋ฅ๋ฅผ ์์ฑ/์ฌ์ฉํ๋ ค๊ณ ํ ๋ ์ค๋ฅ๋ฅผ ๋์ง๋ ๋ฐ ๊ด๋ํฉ๋๋ค.
// will throw TypeError when `config` argument has more than one property
const fake = sinon.fake({
resolves: true,
returns: true
});
๋ถ๋ณ์ฑ์ ์๋ฐํ๋ฏ๋ก .withArgs
์ ์ธ
// will return a Promise that resolves to 'apple pie'
var fake = sinon.fake({resolves: 'apple pie'})
// will return a Promise that rejects with the provided Error, or
// creates a generic Error using the input as message
var fake = sinon.fake({rejects: new TypeError('no more pie')});
var fake = sinon.fake({rejects: 'no more pie'});
// returns the value passed
var fake = sinon.fake({returns: 'apple pie'});
// throws the provided Error, or creates a generic Error using the
// input as message
var fake = sinon.fake({throws: new RangeError('no more pie')});
var fake = sinon.fake({throws: 'no more pie'});
// replace a method with a fake
var fake = sinon.replace(myObject, 'methodName', sandbox.fake({
returns: 'apple pie'
}))
// .. or use the helper method, which will use `sandbox.replace` and `
// sinon.fake`
var fake = sinon.setFake(global, 'methodName', {
returns: 'apple pie'
});
// create an async fake
var asyncFake = sinon.asyncFake({
returns: 'apple pie'
});
fake
๊ฐ ์ฌ๊ธฐ์์ ์ฌ์ฉํ๊ธฐ์ ๊ฐ์ฅ ์ข์ ๋ช
์ฌ์ธ์ง๋ ๋ชจ๋ฅด๊ฒ ์ง๋ง, ํ์ฉ์ฌ๋ ๋์ฌ์ ์ฝ๋งค์ด์ง ์๊ณ ๋ช
์ฌ๋ฅผ ์ฌ์ฉํ๋ ๊ด์ต์ ๊ณ ์ํด์ผ ํ๋ค๊ณ ์๊ฐํฉ๋๋ค.
์ด๊ฒ์ ๋ด๊ฐ ์ ์ ๋์ ๊ณ ๋ คํ ๊ฒ์ ๋๋ค. ์ ๊ธฐ๋ณธ ์๋๋ฐ์ค๋ฅผ ๋ง๋ค์ง ์์ต๋๊น? ์ฌ๋๋ค์ด ๋ณ๋์ ์๋๋ฐ์ค๊ฐ ํ์ํ ๊ฒฝ์ฐ์๋ ์์ฑํ ์ ์์ต๋๋ค.
sinon.*
๋ฅผ ํตํด ๋
ธ์ถ๋๋ ๋ชจ๋ ๋ฉ์๋์ ์ฌ์ฉ๋๋ ๊ธฐ๋ณธ ์๋๋ฐ์ค๋ฅผ ๋ง๋ค์ด์ผ ํฉ๋๋ค.
์ด๊ฒ์ sinon.stub
๊ฐ sandbox.stub
์ ๊ฐ๊ฒ ๋๋ค๋ ๊ฒ์ ์๋ฏธํ๋ฉฐ, ์ด๋ sinon.stub
๋ฅผ ์ฌ์ฉํ์ฌ ์์ฑ์ ์คํ
ํ ์ ์๋ค๋ ์ ํ์ ์ ๊ฑฐํฉ๋๋ค.
sandbox.replace
sandbox.replace
๋ฅผ ์์ฑํ๊ณ ์ด๋์๋ ๋ฌด์์ด๋ ๋์ฒดํ๋ ๋ชจ๋ ์์
์ ์ด๋ฅผ ์ฌ์ฉํฉ๋๋ค. ์ด๊ฒ์ sinon.replace
๋ก ๋
ธ์ถํ๊ณ ์ด ๋ฐฉ๋ฒ์ ์ฌ์ฉํ ๋ ๊ธฐ๋ณธ ์๋๋ฐ์ค๋ฅผ ์ฌ์ฉํฉ๋๋ค.
์ด๊ฒ์ ์๋ง๋ ์ฝ๊ฐ์ ์ฌ๊ฐํ ์ ๋ ฅ ์ ํจ์ฑ ๊ฒ์ฌ๊ฐ ์์ด์ผ ํ๋ฏ๋ก ํจ์๋ฅผ ํจ์๋ก, ์ ๊ทผ์๋ฅผ ์ ๊ทผ์๋ก ๋ฐ๊พธ๋ ์์ผ๋ก๋ง ๋์ฒดํฉ๋๋ค.
@sinonjs/core ํ
์ข์ ์ ์์ด์ผ, ๋ชจ๊ฑด. ์ฌ๋ ค์ฃผ์
์ ๊ฐ์ฌํฉ๋๋ค. ๋๋ ๋ํ stub
API๊ฐ ํผ๋์ค๋ฝ๋ค๊ณ ์๊ฐํ๋ฉฐ ๊ทํ์ ์ ์์ ๋ชจ๋ ์ข์ํฉ๋๋ค. ๋ค์์ ๋ช ๊ฐ์ง ์๊ฐ์
๋๋ค.
sinon.fake
์ฌ๊ธฐ์ ๋ถ๋ณ์ฑ์ด ํต์ฌ์ด๋ผ๋ ๋ฐ ๋์ํฉ๋๋ค. ๊ทธ๋ฌ๋ ํ์ฌ ์คํ ์ผ๋ก ๊ฐ๋ฅํ ์ผ๋ถ "์ ์์ ์ธ" ์ฌ์ฉ ์ฌ๋ก๋ฅผ ํ์ฉํ ์ ์์ต๋๋ค.
์๋ฅผ ๋ค์ด, ๋ค์์ ์ฐ์ถํ๊ณ ๋ฐํํ๋ ์ ํจํ ์ฌ์ฉ ์ฌ๋ก๊ฐ ๋ ์ ์์ต๋๋ค.
sinon.fake({
yields: [null, 42],
returns: true
})
์ฐ๋ฆฌ๋ ์๋ฏธ๊ฐ ์๋ ๊ฒ๊ณผ ๊ทธ๋ ์ง ์์ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
๋ํ callsThrough: true
๋ฅผ ๊ตฌ์ฑ์ผ๋ก ์ง์ํ๋ฉด(๋ชจ๋ ๋์ ์์ฑ๊ณผ ํจ๊ป ์ฌ์ฉํ ์ ์์) "์คํ์ด" API ๋์ ์ ๊ฐ์ง๋ฅผ ์ฌ์ฉํ ์๋ ์์ต๋๋ค. ์ด๊ฒ์ Sinon-speak์์ "spy"์ "stub"์ด ๋ฌด์์ ์๋ฏธํ๋์ง ๋ฐฐ์ฐ๋ ๊ฒ๋ณด๋ค ๋ ์ค์ค๋ก ์ค๋ช
ํ ๊ฒ์
๋๋ค ๐
๊ธฐ๋ณธ ์๋๋ฐ์ค ์ฌ์ฉ
์ด ์์ด๋์ด๊ฐ ๋ง์์ ๋ค๊ธด ํ์ง๋ง ํ
์คํธ ํ sinon.restore()
๋ฅผ ํธ์ถํ๋ฉด ๋ค๋ฅธ ํ
์คํธ์์ ๋จ์ ์ผ๋ถ๋ฅผ ๋๋๋ ค ๋๋ผ์ด ๊ฒฐ๊ณผ ๋๋ ์ด์ ์ ์๋ํ๋ ํ
์คํธ ์คํจ๋ก ์ด์ด์ง ์ ์์ต๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด beforeEach
์ ์ ์ญ ์๋๋ฐ์ค๋ฅผ ์ฌ์ค์ ํ์ฌ ํ
์คํธ ๊ฒฉ๋ฆฌ๋ฅผ ๊ฐ์ ํ ์ ์์ต๋๋ค. ๐
์๋๋ฐ์ค.๊ต์ฒด
๋๋ ์ด๊ฒ์ ๋ง์ด ์ข์ํ๋ค. ๋๋ ์ด๊ฒ์ "์ด๊ฒ์ ๊ฑฐ๊ธฐ์ ๋ถ์ด๊ฒ ๋๋๋" ์ ํธ๋ฆฌํฐ๋ก ์ดํดํฉ๋๋ค. ๋ง์ต๋๊น?
๋ํ ๊ตฌ์ฑ์ผ๋ก callThrough: true๋ฅผ ์ง์ํ๋ฉด(๋ชจ๋ ๋์ ์์ฑ๊ณผ ํจ๊ป ์ฌ์ฉํ ์ ์์) "์คํ์ด" API ๋์ ์๋ก์ด ๊ฐ์ง๋ฅผ ์ฌ์ฉํ ์๋ ์์ต๋๋ค. ์ด๊ฒ์ Sinon-speak์์ "spy"์ "stub"์ด ๋ฌด์์ ์๋ฏธํ๋์ง ๋ฐฐ์ฐ๋ ๊ฒ๋ณด๋ค ๋ ์ค์ค๋ก ์ค๋ช ํ ๊ฒ์ ๋๋ค ๐
๊ทธ๊ฒ์ ์ฐ๋ฆฌ๊ฐ spy
๋๋ stub
๊ฐ ์ ํ ํ์ํ์ง ์๋ค๋ ๊ฒ์ ์๋ฏธํฉ๋๊น?
์๋๋ฐ์ค.๊ต์ฒด
๋๋ ์ด๊ฒ์ ๋ง์ด ์ข์ํ๋ค. ๋๋ ์ด๊ฒ์ "์ด๊ฒ์ ๊ฑฐ๊ธฐ์ ๋ถ์ด๊ฒ ๋๋๋" ์ ํธ๋ฆฌํฐ๋ก ์ดํดํฉ๋๋ค. ๋ง์ต๋๊น?
๋ค, ๋ฐ๋ก ๊ทธ ์์ด๋์ด์์ต๋๋ค. ๋ง์ ์ผ์ ํ๊ธฐ ์ํด ๋์ผํ ๋ฉ์๋( sinon.stub
)๋ฅผ ์ค๋ฒ๋ก๋ํ๋ ๋์ ํ ๊ฐ์ง๋ง ์ํํ๋ ๋ช
์์ ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ญ์์ค.
๊ฐ์กฐ ํ์ํ ๋๋ก fake
API๋ ํ์ฌ ์คํ์ด ๋ฐ ์คํ
์ผ๋ก ๊ฐ๋ฅํ ๋ชจ๋ ๊ฒ์ ์ง์ํ์ง ์์ ๊ฒ์
๋๋ค. ํ์ง๋ง ๋ค, fake
API๋ stub
์ spy
๊ธฐ๋ฅ์ ํตํฉํ ์ ์๋ ๊ธฐํ๋ผ๊ณ ์๊ฐํฉ๋๋ค.
์ด ์์ด๋์ด๊ฐ ๋ง์์ ๋ค๊ธด ํ์ง๋ง ํ ์คํธ ํ sinon.restore()๋ฅผ ํธ์ถํ๋ฉด ๋ค๋ฅธ ํ ์คํธ์์ ๋จ์ ์ผ๋ถ๋ฅผ ๋๋๋ ค ๋๋ผ์ด ๊ฒฐ๊ณผ๋ฅผ ์ด๋ํ ์ ์์ผ๋ฉฐ ์ด์ ์ ์๋ํ๋ ํ ์คํธ๊ฐ ์คํจํ ์ ์์ต๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ํ ์คํธ ๊ฒฉ๋ฆฌ๋ฅผ ๊ฐ์ ํ๊ธฐ ์ํด beforeEach์์ ์ ์ญ ์๋๋ฐ์ค๋ฅผ ์ฌ์ค์ ํ ์ ์์ต๋๋ค. ๐
๊ทธ๊ฒ์ ํ์คํ ์ฃผ์ ๋ณ๊ฒฝ ์ฌํญ์ด๋ฉฐ ๊ฐ๋ณ๊ฒ ๋์ ํด์๋ ์๋ฉ๋๋ค.
fake
๋ฅผ ์์ฑํ ๋ ๋์ ๊ตฌ์ฑ์ ์ ๋ฌํ์ง ์์ผ๋ฉด spy
์ ๋์ผํฉ๋๋ค.
// ~spy, records all calls, has no behaviour
const fake = sinon.fake();
// ~stub, records all calls, returns 'apple pie'
const fake = sinon.fake({
returns: 'apple pie'
});
๊ทธ๋ฌ๋ฉด ์๋ฌด ์์ ๋ ํ์ง ์๋ ์คํ ์ ์ด๋ป๊ฒ ๋ง๋ค ์ ์์ต๋๊น?
๊ทธ๋ฌ๋ฉด ์๋ฌด ์์ ๋ ํ์ง ์๋ ์คํ ์ ์ด๋ป๊ฒ ๋ง๋ค ์ ์์ต๋๊น?
๊ทํ์ ์ง๋ฌธ์ ์์ ํ ์ดํดํ๋์ง ํ์ ํ ์ ์์ง๋ง...
// a fake that has no behaviour
const fake = sinon.fake();
// put it in place of an existing method
sandbox.replace(myObject, 'someMethod', fake);
์, ์ด์ ๋ฌด์จ ๋ง์ธ์ง ์ ๊ฒ ๊ฐ์ต๋๋ค. A fake
๋ ํญ์ stub
์
๋๋ค. ๋น์ ์ด ~spy, records all calls
๋ผ๊ณ ๋งํ์ ๋ ๋๋ "์๋ ํจ์๋ก์ ํธ์ถ"์ ์ดํดํ์ต๋๋ค. ๊ทธ๋ฌ๋ fake
๋ ๋์ฒดํ ํจ์์ ๋ํด ์์ง ๋ชปํฉ๋๋ค. ๋ฐ๋ก sandbox.replace
๊ฐ ํ๋ ์ผ์
๋๋ค.
๋ฐ๋ผ์ ์ด๋ฅผ ์ผ๋์ ๋๊ณ ํ์ฌ spy
๊ธฐ๋ฅ์ ์๋ก์ด ๊ฐ์ง๋ก ์ ์ ์ ์๋ ๋ ๋ค๋ฅธ ์ ์์ด ์์ต๋๋ค.
const fake = sinon.fake(function () {
// Any custom function
});
์ฃผ์ด์ง ํจ์๋ ๊ฐ์ง์ ์ํด ํธ์ถ๋ฉ๋๋ค. ์ด API๋ฅผ ์ฌ์ฉํ๋ฉด ๋ค๋ฅธ ๋์๊ณผ ํผํฉํ ์ ์์ต๋๋ค. ์ฌ์ค, config ๊ฐ์ฒด๋ ์ง์ ๋ ๋์์ ๊ตฌํํ๋ ํจ์๋ฅผ ๋ง๋ ๋ค์ ์ด๋ฅผ ๊ฐ์ง์ ์ ๋ฌํฉ๋๋ค.
sandbox.spy(object, method)
๊ตฌํ์ ๋ค์๊ณผ ๊ฐ์ด ๋ ์ ์์ต๋๋ค.
const original = object[method];
const fake = sinon.fake(original);
sandbox.replace(object, method, fake);
๊ธฐ๋ณธ์ ์ผ๋ก ํ์ค์์ฝ ๐ค
๋ค. ์ผ์ ๋จ์ํํ๋ฉด ์ฌ๋ฏธ์ ์์ต ๐ฐ์ ์ํด ๋ค์ ๋ฏน์ฑ์ ์์ํ ์ ์์ต๋๋ค.
๊ทธ๋ฌ๋ fake
์ฌ์ฉํ๊ณ ๋ ์ด์ spy
๋ฐ stub
๋ฅผ ์ฌ์ฉํ์ง ์์ผ๋ ค๋ ๊ฒฝ์ฐ ์ด ๋ ๊ฐ์ง๋ฅผ ๊ทธ๋๋ก ๋๋ ๊ฒ์ด ์ข์ต๋๋ค.
์ฌ๊ธฐ์ "๋ค์" API์ ๋ํด ์๊ฐํ๊ณ ์์ต๋๋ค. ์ด๋๊ฐ์ ๋์ฒด ๋
ผ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด sandbox.spy
๊ฐ ํ์ํฉ๋๋ค. ๋ด๊ฐ ์ดํดํ๊ธฐ๋ก๋ ์ด์ ๋ฒ์ ๊ณผ ํธํ๋์ด์ผ ํฉ๋๋ค. ๊ทธ๋ฌ๋ฉด stub
๊ตฌํ์ด ๋ ์ด์ ์ฌ์ฉ๋์ง ์์ ์ ์์ต๋๋ค.
์ด๋๊ฐ์ ๊ต์ฒด ๋ ผ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด sandbox.spy๊ฐ ํ์ํฉ๋๋ค. ๋ด๊ฐ ์ดํดํ๊ธฐ๋ก๋ ์ด์ ๋ฒ์ ๊ณผ ํธํ๋์ด์ผ ํฉ๋๋ค. ๊ทธ๋ฌ๋ฉด ์คํ ๊ตฌํ์ด ๋ ์ด์ ์ฌ์ฉ๋์ง ์์ ์ ์์ต๋๋ค.
ํ๋ก์ฐํ๊ณ ์๋์ง ์ ๋ชจ๋ฅด๊ฒ ์ต๋๋ค. ์์ธํ ์ค๋ช ํด ์ฃผ์๊ฒ ์ต๋๊น?
ํ์ ํ๋. ๊ทํ์ ์ ์์ ์ดํดํ๋ ํ ๊ทํ๋ ์ง๋์น๊ฒ ๋ณต์กํ stub
API๋ฅผ ๋์ฒดํ๊ธฐ๋ฅผ ์ํฉ๋๋ค. ์คํ
์ด ํ์ฌ ๊ตฌํ๋๋ ๋ฐฉ์์ ๋์์ ๊ตฌํํ๋ ํจ์๋ก spy
๋ฅผ ๋ง๋๋ ๊ฒ์
๋๋ค. ๋ด๊ฐ ์ ์ํ๋ ๊ฒ์ fake
API๋ฅผ ์ฌ์ฉํ์ฌ ๋์ผํ ์์
์ ์ํํ๊ณ ๋ด๋ถ์ ์ผ๋ก spy
๋ฅผ ์์ฑํ๋ ๊ฒ์
๋๋ค. ๊ทธ๋ฌ๋ ์ฐ๋ฆฌ๋ ์ฐ๊ฒฐ์ ์ ๊ฑฐํ๊ณ ์ถ๊ธฐ ๋๋ฌธ์ ๋ ์ด์ ๋์์ ๋ฐํํ์ง ์์ต๋๋ค. . ์ฐ๋ฆฌ๋ ๊ทธ๋ฅ ์คํ์ด๋ฅผ ๋ฐํํฉ๋๋ค. ์ด๊ฒ์ fake
๊ตฌํ์ stub
์ ๋์์ผ๋ก ๋ง๋ค๊ณ ๋ฐํ๋ ํจ์๋ ํ์ฌ ๋ชจ๋ Sinon API์ ํธํ๋ฉ๋๋ค. ๊ทธ๊ฒ์ด ์๋ฏธ๊ฐ ์์ต๋๊น? ์๋๋ฉด ๋ด๊ฐ ๋ญ๊ฐ๋ฅผ ๋์น๊ณ ์์ต๋๊น?
์ข์์, ์ฐ๋ฆฌ๋ ๋น์ทํ ์ดํด๋ฅผ ํ๊ณ ์๋ ๊ฒ ๊ฐ์์ ๐
๋ค์ ๋ฐ๋ณตํ์๋ฉด, ์ฐ๋ฆฌ๊ฐ ๋ญ๊ฐ๋ฅผ ๋์น ๊ฒฝ์ฐ๋ฅผ ๋๋นํ์ฌ ๋ค๋ฅธ ๊ธฐ์ฌ์๊ฐ ๋์ผํ ์ดํด๋ฅผ ๊ฐ์ง ์ ์๋๋ก ํฉ๋๋ค.
sandbox.replace
(ํ์ฌ stub
์ ์์)sinon
์๋ sinon.reset
๋ฐ sinon.restore
๋ฅผ ํ์ฉํ๋ ๊ธฐ๋ณธ ์๋๋ฐ์ค๊ฐ ์์ต๋๋ค(์ด๋ฅผ ๋ณํฉํด์ผ ํฉ๋๊น?)sinon.fake
โ ๋ชจ๋ ํธ์ถ์ ๊ธฐ๋กํ๋ ํจ์์ ๋ํ ๋ณ๊ฒฝ ๋ถ๊ฐ๋ฅํ๊ณ ํ๋ก๊ทธ๋๋ฐ ๊ฐ๋ฅํ ๋์ฒดsinon.spy
sinon.stub
// effectively a spy that has no target
const fake = sinon.fake()
// spy on a function
const fake = sinon.fake(console.log);
const fake = sinon.fake(function() { return 'apple pie'; });
// a shorthand construction of fake with behaviour
const fake = sinon.fake({
returns: 'apple pie'
});
// replacing an existing function with a fake
var fakeLog = sinon.fake();
sandbox.replace(console, 'log', fakeLog);
์ด ์ํ์์ ์ ์์ Function
์ฒ๋ฆฌํฉ๋๋ค. ํจ์๊ฐ ์๋ ์์ฑ๊ณผ ์ ๊ทผ์์ ๋ํด ๋ฌด์์ ํด์ผ ํ๋์ง ๊ณ ๋ คํด์ผ ํฉ๋๋ค. ์ต์ํ ์ ์์ ์ธ ๊ต์ฒด๋ง ํ์ฉํ๋๋ก sandbox.replace
์ ์ ํํ ์ ์๋์ง ํ์ธํด์ผ ํฉ๋๋ค.
์ด๊ฒ์ sinon.stub()
๋ฐ sinon.spy()
๋ ๋ค ์์ผ๋ก ๋ ์ด์ ์ฌ์ฉ๋์ง ์๊ณ sinon.fake()
๋ฅผ ์ํด ๋ด๋ถ์ ์ผ๋ก ๋ค์ ์คํ๋๋ค๋ ๊ฒ์ ์๋ฏธํฉ๋๊น? ๊ทธ๋ ๋ค๋ฉด ๋ณธ์ง์ ์ผ๋ก TestDouble์ ์๊ฐ ์ ํฅํด ๋์๊ฐ๊ณ ์์ต๋๋ค. IMHO๊ฐ ๋ฐ๋์ ๋์ ๊ฒ์ ์๋์ง๋ง, ๋ง์ ์ฌ๋๋ค์ด sinon.fake()
์ ๋ํด ๋ชจ๋ Sinon API ํธ์ถ์ ๋์ฒดํด์ผ ํ๋ค๋ ๊ฒ์ ์๊ฒ ๋๋ฉด ๋ค๋ฅธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ต๋๋ค(๋น๋ก ์ฆ, Sinon์ API์ ๋ํ ๊ธฐ์กด ์ง์์ ๋ชจ๋ ์๊ฒ ๋ฉ๋๋ค.
์ด๊ฒ์ sinon.stub() ๋ฐ sinon.spy() ๋ ๋ค ๋ฏธ๋์ ๋ ์ด์ ์ฌ์ฉ๋์ง ์๊ณ sinon.fake()๋ฅผ ์ํด ์ฌ์ฉ๋จ์ ์๋ฏธํฉ๋๊น, ์๋๋ฉด ๋ด๋ถ์ ์ผ๋ก ๋ค์ ์คํํฉ๋๊น? ๊ทธ๋ ๋ค๋ฉด ์ฐ๋ฆฌ๋ ๋ณธ์ง์ ์ผ๋ก TestDouble์ ์๊ฐ์ ํฅํด ๋์๊ฐ๊ณ ์์ต๋๋ค.
์ข ๊ฒน์น๋ ๊ฒ ๊ฐ์์. ์ด ์ ์์ ๋ํ ๋์ ์ฃผ์ ๋๊ธฐ๋ ๋ถ๋ณ ๋์์ ๊ฐ์ง ๊ฐ์ง ํจ์๋ฅผ ๊ฐ๋ ๊ฒ์ ๋๋ค.
IMHO๊ฐ ๋ฐ๋์ ๋์ ๊ฒ์ ์๋์ง๋ง ๋ง์ ์ฌ๋๋ค์ด sinon.fake()์ ๋ํ ๋ชจ๋ Sinon API ํธ์ถ์ ์ด์จ๋ ๊ต์ฒดํด์ผ ํ๋ค๋ ๊ฒ์ ์๊ฒ ๋๋ฉด ๋ค๋ฅธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ ์๋ ์๋ค๋ ์ ์ ๊ณ ๋ คํด ๋ณผ ๊ฐ์น๊ฐ ์์ต๋๋ค. ์ด๋ Sinon์ API์ ๋ํ ๊ธฐ์กด ์ง์์ ๋ชจ๋ ์๊ฒ ๋๋ค๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค).
์ฌ๋๋ค์ด ๋ค๋ฅธ ๋์๊ด์ด ์์ ์ ํ์๋ฅผ ๋ ์ ์ถฉ์กฑ์ํจ๋ค๋ ๊ฒ์ ์๊ฒ ๋๋ค๋ฉด ์ฐ๋ฆฌ๊ฐ ๊ทธ๋ค์ด ๊ทธ๊ฒ์ ๋ฐฐ์ฐ๋ ๋ฐ ๋์์ด ๋์ด ๊ธฐ์ฉ๋๋ค. :)
๊ทธ๋ฌ๋ ์คํ์ด ๋ฐ ์คํ ๋ฉ์๋๋ฅผ ์ ์งํ๊ฑฐ๋ ๋ ์ด์ ์ฌ์ฉํ์ง ์๊ณ ๊ธฐ๋ฅ์ ์ผ๋ถ ์ถ์ํ ์ ์์ต๋๊น? ๊ทธ๊ฒ์ ๋์๊ฒ ๋ถ๋ถ๋ช ํ๋ค.
๊ทธ๋ฌ๋ ์คํ์ด ๋ฐ ์คํ ๋ฉ์๋๋ฅผ ์ ์งํ๊ฑฐ๋ ๋ ์ด์ ์ฌ์ฉํ์ง ์๊ณ ๊ธฐ๋ฅ์ ์ผ๋ถ ์ถ์ํ ์ ์์ต๋๊น?
fake
๊ฐ ์์ ์ ์ผ๋ก ๋ณด์ด๋ฉด spy
๋ฐ stub
๋ฅผ ๋ ์ด์ ์ฌ์ฉํ์ง ์๊ณ ์ฌ๋๋ค์ด ์
๊ทธ๋ ์ด๋ํ ์ ์๋๋ก 1๋
์ ์ ๊ณตํฉ๋๋ค.
์ฌ๋๋ค์ด ์ฝ๋๋ฅผ ์ฎ๊ธฐ๋ ๋ฐ ๋์์ด ๋๋๋ก codemod์ ํ๋ฅญํ ๋ฌธ์๋ฅผ ์ ๊ณตํ๊ธฐ ์ํด ์ต์ ์ ๋คํด์ผ ํ๋ค๊ณ ์๊ฐํฉ๋๋ค.
์ ๋ ์ด ๋ถ๋ถ(๊ธฐ๋ณธ ์๋๋ฐ์ค)์ ์ฒซ ๋ฒ์งธ ๋ถ๋ถ์ ๋ํ ๋ถ๊ธฐ ์์
์ ํ๊ณ ์์ต๋๋ค. sandbox
์ collection
๊ฐ ์ด์ ํ๋๊ฐ ๋๋๋ก ์ฝ๋๋ฅผ ๋ฆฌํฉํ ๋งํ์ต๋๋ค. ๊ธฐ๋ณธ ์๋๋ฐ์ค๊ฐ ์๋ํ๋๋ก ํ์ต๋๋ค.
๋๋ ์์ผ๋ก ๋ฉฐ์น ๋์ ์ปค๋ฐ์ ์ ๋ฆฌํ๊ณ ์ ๋ฐ์ดํธ๋ API๋ฅผ ์ํด ์ด ๋ฆฌํฌ์งํ ๋ฆฌ์ ๋ถ๊ธฐ๋ฅผ ๋ง๋ค ๊ฒ์ ๋๋ค.
์ด๊ฒ์ ์ข์ ์์ด๋์ด์ ๋๋ค. ์์ฃผ ์ ์ฐ์ฌ์ก์ต๋๋ค.
๋๋ ๋ํ ์คํ ๊ณผ ์คํ์ด์ ์ฌ์ฉ ์ค๋จ ํต์ง๋ฅผ ์ถ๊ฐํ ๊ฒ์ ๋๋ค.
๋ํ ํจ์๋ฅผ ์ ๋ฌํ์ฌ ํค๊ฐ ์๋ ๊ฐ์ฒด ์ ๋ฌ์ ๋ณ๊ฒฝํ๋ ๋ฐฉ๋ฒ์ ๋ํด์๋ ์๊ฐํ๊ณ ์์์ต๋๋ค.
์ด๋ ๊ฒ ํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ์ด์ ์ด ์ถ๊ฐ๋ฉ๋๋ค.
typescript
๋๋ ๋ค๋ฅธ ์ข
๋ฅ์ ์ ์ ๊ฒ์ฌ๊ธฐ๋ฅผ ์ฌ์ฉํ๋ ค๋ ์ฌ์ฉ์๋ฅผ ์ํด ํด๋น ํจ์์ type
๋ฅผ ์ถ๊ฐํ ์ ์์ต๋๋ค.๋ฐ๋ผ์ API๋ ๋์ ๋ค์๊ณผ ๊ฐ์ด ํ์๋ฉ๋๋ค.
// It would be cool to allow users to import these using destructuring to make code more concise
import { resolves, rejects, returns } from 'sinon/behaviors';
var fake = sinon.fake(resolves('apple pie'))
var fake = sinon.fake(rejects(new TypeError('no more pie')));
var fake = sinon.fake(rejects('no more pie'));
var fake = sinon.fake(returns('apple pie'));
var fake = sinon.fake(throws(new RangeError('no more pie'));
var fake = sinon.fake(throws('no more pie'));
์ด๊ฒ์ ๊ตฌํํ ๋ ๋น์ ์ด ์ ์ํ๋ ๊ฒ๊ณผ ๊ฐ์ ๋งค์ฐ ๋จ์ํ ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ ๋ฌธ์ ์ผ ์ ์์ต๋๋ค. ๊ทธ๋ฐ ๋ค์, ํ๋ ์ด์์ ๋์์ด ์๋ ๊ฒฝ์ฐ ๋ณํฉํ ์ ์์ต๋๋ค.
๋ํ onThirdCall
๋ฐ withArgs
$์ ๊ฐ์ ํญ๋ชฉ์ ํผํฉํ๋ ๊ฒฝ์ฐ ์ด๋ฌํ ๊ฒฝ์ฐ์ ์ด๋ค ์ผ์ด ๋ฐ์ํ๋์ง ๋ฌธ์ํํด์ผ ํ๋ค๊ณ ์๊ฐํฉ๋๋ค.
๋๋ฌด ๋ฆ๊ฒ ๋ฆฌ๋ทฐํด์ ์ฃ์กํฉ๋๋ค. ์ง๋ ๋ช ๊ฐ์์ ๋งค์ฐ ๋ฐ๋นด์ต๋๋ค.
@lucasfcosta PR #1586์ ํ์ธํ์ธ์.
์ด ๋ฌธ์ ๋ ์ต๊ทผ ํ๋์ด ์์๊ธฐ ๋๋ฌธ์ ์๋์ผ๋ก ์ค๋๋ ๊ฒ์ผ๋ก ํ์๋์์ต๋๋ค. ๋ ์ด์ ํ๋์ด ์์ผ๋ฉด ํ์๋ฉ๋๋ค. ๊ทํ์ ๊ธฐ์ฌ์ ๊ฐ์ฌ๋๋ฆฝ๋๋ค.
5.0.0 ์ด์ ๋ฒ์ ์ package.json์ ์ดํ 5.0.0-next.* ์ํํ ๋ฒ์ ์์ ๋ฌธ์ ๋ฅผ ์ผ์ผํค๊ณ ์์ต๋๋ค. 5.0.0์ด ๋ชจ๋ ์ํํ ๋ฒ์ ๋ณด๋ค ํฌ๊ธฐ ๋๋ฌธ์ ๋๋ค.
5.0.0์ด ๋์๊ธฐ ๋๋ฌธ์ next
ํ๋ฆฌ๋ฆด๋ฆฌ์ฆ ์์น๋ฅผ 5.0.1-next.1
๋ก ๋๋ ค์ผ ํ๋ค๊ณ ์๊ฐํฉ๋๋ค.
๋ด๊ฐ ์ฌ์ฉํ๊ณ ์๋ ๋ค๋ฅธ ํจํค์ง๊ฐ ๋ ์ด์ ์ฌ์ฉ๋์ง ์๋ ๋ฉ์์ง๋ฅผ ๋ฐ๊ณ ํจํค์ง์ package.json์ด "sinon": "^5.0.0-next.4"
์ ์์กดํ๊ธฐ ๋๋ฌธ์ ์ด๊ฒ์ ์์์ฐจ๋ ธ์ต๋๋ค.
npm WARN deprecated [email protected]: this version has been deprecated
์ด๊ฒ์ด ์ํํ ๋ฌธ์ ์ ๋ํ ์ ๋ฌธ์ ๋ฅผ ์ด โโ๊ฐ์น๊ฐ ์๋์ง ํ์คํ์ง ์์๊ธฐ ๋๋ฌธ์ ์ฌ๊ธฐ์ ๋๊ธ์ด ๊ฐ์ฅ ์์ ํ ๊ฒ ๊ฐ์์ต๋๋ค.
๋ ๋ค๋ฅธ ํด๊ฒฐ์ฑ ์ ๋ค์ ์ฃผ ๋ฒ์ ์ ์ถ์ํ๋ ๊ฒ์ ๋๋ค. @sinonjs/core๋ ์ด๋ป๊ฒ ์๊ฐํ์ธ์?
@mroderick v5์ ๋ชจ๋ ๋ณ๊ฒฝ ์ฌํญ์ด ๋ฌด์์ธ์ง ๋ ์ด์ ๋งํ ์ ์์ต๋๋ค. ๋์ ๋ง์ง๋ง ํ ์คํธ์์ ๊ทธ๊ฒ์ ์ ์๋ํ๊ณ ๋๋ ์๋ก์ด ๊ฐ์ง๋ฅผ ์ฌ์ฉํ๊ธฐ๋ฅผ ๊ณ ๋ํ๊ณ ์์ต๋๋ค. ์๋ก์ด ์ ๊ณต์ด๋ผ ์ด์ ๋ณด๋ด์ฃผ์ธ์ ๐
๋ค์ ์ฃผ ๋ฒ์ ์ ์ถ์ํ๊ธฐ ์ ์ ๋ณํฉํ๊ณ ์ถ์ PR #1764๊ฐ ํ๋ ๋ ์์ต๋๋ค.
[email protected]
์(๋ฅผ) ๊ฒ์ํ์ต๋๋ค. ๊ทธ ๋์ ์ฌ๋๋ค์ ์ถ์ด ๋ ์ฌ์์ง๊ธฐ๋ฅผ ๋ฐ๋๋๋ค.
๊ฐ์ฌํฉ๋๋ค. package.json์์ ์ข
์์ฑ์ ํ
์คํธํ์ผ๋ฉฐ(ํญ์ ๋ค์ ํ์ธํ๋ ๊ฒ์ด ์ข์ต๋๋ค) "sinon": "^5.0.1"
๋ ์ผ์นํ๋ ํญ๋ชฉ์ด ์๊ธฐ ๋๋ฌธ์ ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค(์์ง ๋ฆด๋ฆฌ์ค ์์). "sinon": "^5.0.1-next.1"
ํด๋น ๋ฒ์ ์ ๊ฐ์ ธ์ค๋ ๋ฐ ์ ๋๋ก ์๋ํฉ๋๋ค.
์ด๊ฒ์ ๊ฒฐ์ฝ ํฐ ๋ฌธ์ ๊ฐ ์๋์์ต๋๋ค. ํนํ v5๊ฐ ํ๋์ ๊ฐ๋ฐ ์ค์ด์๊ธฐ ๋๋ฌธ์ ๊ทธ๊ฒ์ด ์ถ์๋ ๋๊น์ง ์ผ๋ง๋ ์ค๋ ๊ฑธ๋ ธ๋์ง ํ์ ํ ์ ์์์ ๋ ํนํ ๋น์ ์๊ฒ ์๋ ค์ค ๊ฐ์น๊ฐ ์๋ค๊ณ ์๊ฐํ์ต๋๋ค. ๊ฐ๊น์ด ์์ผ ๋ด์ ์ถ์ํ๋ ๊ฒ์ด ์ข์ ์์ด๋์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค.
fake
๋ #1768๊ณผ ํจ๊ป ๋์
๋์ด [email protected]
๊ฐ ๋์์ต๋๋ค.
๊ฐ์ฅ ์ ์ฉํ ๋๊ธ
์ข์์, ์ฐ๋ฆฌ๋ ๋น์ทํ ์ดํด๋ฅผ ํ๊ณ ์๋ ๊ฒ ๊ฐ์์ ๐
๋ค์ ๋ฐ๋ณตํ์๋ฉด, ์ฐ๋ฆฌ๊ฐ ๋ญ๊ฐ๋ฅผ ๋์น ๊ฒฝ์ฐ๋ฅผ ๋๋นํ์ฌ ๋ค๋ฅธ ๊ธฐ์ฌ์๊ฐ ๋์ผํ ์ดํด๋ฅผ ๊ฐ์ง ์ ์๋๋ก ํฉ๋๋ค.
TL;DR
sandbox.replace
(ํ์ฌstub
์ ์์)sinon
์๋sinon.reset
๋ฐsinon.restore
๋ฅผ ํ์ฉํ๋ ๊ธฐ๋ณธ ์๋๋ฐ์ค๊ฐ ์์ต๋๋ค(์ด๋ฅผ ๋ณํฉํด์ผ ํฉ๋๊น?)sinon.fake
โ ๋ชจ๋ ํธ์ถ์ ๊ธฐ๋กํ๋ ํจ์์ ๋ํ ๋ณ๊ฒฝ ๋ถ๊ฐ๋ฅํ๊ณ ํ๋ก๊ทธ๋๋ฐ ๊ฐ๋ฅํ ๋์ฒดsinon.spy
sinon.stub
์ด ์ํ์์ ์ ์์
Function
์ฒ๋ฆฌํฉ๋๋ค. ํจ์๊ฐ ์๋ ์์ฑ๊ณผ ์ ๊ทผ์์ ๋ํด ๋ฌด์์ ํด์ผ ํ๋์ง ๊ณ ๋ คํด์ผ ํฉ๋๋ค. ์ต์ํ ์ ์์ ์ธ ๊ต์ฒด๋ง ํ์ฉํ๋๋กsandbox.replace
์ ์ ํํ ์ ์๋์ง ํ์ธํด์ผ ํฉ๋๋ค.