Sinon: ๋ฏธ๋ž˜ ์ด์ •ํ‘œ์— ๋Œ€ํ•œ ์•„์ด๋””์–ด

์— ๋งŒ๋“  2017๋…„ 09์›” 13์ผ  ยท  31์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: sinonjs/sinon

๋ฐฐ๊ฒฝ

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

์ŠคํŒŒ์ด API ์‚ฌ์šฉ

๋ถˆ๋ณ€์„ฑ์„ ์œ„๋ฐ˜ํ•˜๋ฏ€๋กœ .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 ๊ฐ€ ์—ฌ๊ธฐ์—์„œ ์‚ฌ์šฉํ•˜๊ธฐ์— ๊ฐ€์žฅ ์ข‹์€ ๋ช…์‚ฌ์ธ์ง€๋Š” ๋ชจ๋ฅด๊ฒ ์ง€๋งŒ, ํ˜•์šฉ์‚ฌ๋‚˜ ๋™์‚ฌ์— ์–ฝ๋งค์ด์ง€ ์•Š๊ณ  ๋ช…์‚ฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ด€์Šต์„ ๊ณ ์ˆ˜ํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

์ œ์•ˆ๋œ API ๋ณ€๊ฒฝ ์‚ฌํ•ญ

๊ธฐ๋ณธ ์ƒŒ๋“œ๋ฐ•์Šค ์‚ฌ์šฉ

์ด๊ฒƒ์€ ๋‚ด๊ฐ€ ์ž ์‹œ ๋™์•ˆ ๊ณ ๋ คํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์™œ ๊ธฐ๋ณธ ์ƒŒ๋“œ๋ฐ•์Šค๋ฅผ ๋งŒ๋“ค์ง€ ์•Š์Šต๋‹ˆ๊นŒ? ์‚ฌ๋žŒ๋“ค์ด ๋ณ„๋„์˜ ์ƒŒ๋“œ๋ฐ•์Šค๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

sinon.* ๋ฅผ ํ†ตํ•ด ๋…ธ์ถœ๋˜๋Š” ๋ชจ๋“  ๋ฉ”์„œ๋“œ์— ์‚ฌ์šฉ๋˜๋Š” ๊ธฐ๋ณธ ์ƒŒ๋“œ๋ฐ•์Šค๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
์ด๊ฒƒ์€ sinon.stub ๊ฐ€ sandbox.stub ์™€ ๊ฐ™๊ฒŒ ๋œ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•˜๋ฉฐ, ์ด๋Š” sinon.stub ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์†์„ฑ์„ ์Šคํ…ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ œํ•œ์„ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.

sandbox.replace

sandbox.replace ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์–ด๋””์„œ๋‚˜ ๋ฌด์—‡์ด๋“  ๋Œ€์ฒดํ•˜๋Š” ๋ชจ๋“  ์ž‘์—…์— ์ด๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์„ sinon.replace ๋กœ ๋…ธ์ถœํ•˜๊ณ  ์ด ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•  ๋•Œ ๊ธฐ๋ณธ ์ƒŒ๋“œ๋ฐ•์Šค๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ์•„๋งˆ๋„ ์•ฝ๊ฐ„์˜ ์‹ฌ๊ฐํ•œ ์ž…๋ ฅ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๊ฐ€ ์žˆ์–ด์•ผ ํ•˜๋ฏ€๋กœ ํ•จ์ˆ˜๋ฅผ ํ•จ์ˆ˜๋กœ, ์ ‘๊ทผ์ž๋ฅผ ์ ‘๊ทผ์ž๋กœ ๋ฐ”๊พธ๋Š” ์‹์œผ๋กœ๋งŒ ๋Œ€์ฒดํ•ฉ๋‹ˆ๋‹ค.

Feature Request Improvement Needs investigation pinned

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

์ข‹์•„์š”, ์šฐ๋ฆฌ๋„ ๋น„์Šทํ•œ ์ดํ•ด๋ฅผ ํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ ๊ฐ™์•„์š” ๐Ÿ‘

๋‹ค์‹œ ๋ฐ˜๋ณตํ•˜์ž๋ฉด, ์šฐ๋ฆฌ๊ฐ€ ๋ญ”๊ฐ€๋ฅผ ๋†“์นœ ๊ฒฝ์šฐ๋ฅผ ๋Œ€๋น„ํ•˜์—ฌ ๋‹ค๋ฅธ ๊ธฐ์—ฌ์ž๊ฐ€ ๋™์ผํ•œ ์ดํ•ด๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

TL;DR

  • ๋ชจ๋“  ๊ต์ฒด ๋Š” ์ƒˆ๋กœ์šด ์œ ํ‹ธ๋ฆฌํ‹ฐ๋กœ ์ˆ˜ํ–‰๋ฉ๋‹ˆ๋‹ค: 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 ์„ ์ œํ•œํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋ชจ๋“  31 ๋Œ“๊ธ€

@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์™€ ํ˜ธํ™˜๋ฉ๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์ด ์˜๋ฏธ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ? ์•„๋‹ˆ๋ฉด ๋‚ด๊ฐ€ ๋ญ”๊ฐ€๋ฅผ ๋†“์น˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ?

์ข‹์•„์š”, ์šฐ๋ฆฌ๋„ ๋น„์Šทํ•œ ์ดํ•ด๋ฅผ ํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ ๊ฐ™์•„์š” ๐Ÿ‘

๋‹ค์‹œ ๋ฐ˜๋ณตํ•˜์ž๋ฉด, ์šฐ๋ฆฌ๊ฐ€ ๋ญ”๊ฐ€๋ฅผ ๋†“์นœ ๊ฒฝ์šฐ๋ฅผ ๋Œ€๋น„ํ•˜์—ฌ ๋‹ค๋ฅธ ๊ธฐ์—ฌ์ž๊ฐ€ ๋™์ผํ•œ ์ดํ•ด๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

TL;DR

  • ๋ชจ๋“  ๊ต์ฒด ๋Š” ์ƒˆ๋กœ์šด ์œ ํ‹ธ๋ฆฌํ‹ฐ๋กœ ์ˆ˜ํ–‰๋ฉ๋‹ˆ๋‹ค: 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 ๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์‚ฌ์šฉ์ž๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋™์ž‘์— ๋Œ€ํ•œ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋ ค๊ณ  ํ•  ๋•Œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
  • ์šฐ๋ฆฌ๋Š” ์ด๋Ÿฌํ•œ ๊ธฐ๋Šฅ์„ ๋ณ„๋„๋กœ ๋ฌธ์„œํ™”ํ•˜๊ณ  ๋ฌธ์„œ๋ฅผ ํ›จ์”ฌ ๋” ์ข‹๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ด๋Ÿฌํ•œ ๋™์ž‘์— ์˜๋ฏธ๊ฐ€ ์—†๋Š” ์ธ์ˆ˜๋ฅผ ์ „๋‹ฌํ•  ๋•Œ ์œ ์šฉํ•œ ์˜ค๋ฅ˜๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์„ ํƒ์ /๋‘˜ ์ด์ƒ์˜ ์ธ์ˆ˜๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • (์ด ๊ฒฝ์šฐ ๋งŽ์€ ๊ฒฝ์šฐ๋ฅผ ๋ณด์ง€๋Š” ๋ชปํ–ˆ์ง€๋งŒ) ์ผ์„ ๋” ๊ตฌ์„ฑ ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋งŒ๋“ค๊ณ  ์‚ฌ๋žŒ๋“ค์ด ์ƒ์„ฑ๋œ ๋™์ž‘์„ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
  • IMO ์ด๊ฒƒ์€ ๋˜ํ•œ ๋™์ž‘์ด ์žˆ๋Š” ๊ฐ์ฒด๋ฅผ ๊ฐ–๋Š” ๊ฒƒ๋ณด๋‹ค ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ 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] ๊ฐ€ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰