Sinon: ์ƒŒ๋“œ ๋ฐ•์Šค์—์„œ '์กด์žฌํ•˜์ง€ ์•Š๋Š” ์†์„ฑ์„ ์Šคํ… ํ•  ์ˆ˜ ์—†์Œ'์˜ค๋ฅ˜ ๋ฐœ์ƒ

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

2.4.1์—์„œ 3.2.1๋กœ ์—…๊ทธ๋ ˆ์ด๋“œ๋ฅผ ์‹œ๋„ํ–ˆ๋Š”๋ฐ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด ์ฝ”๋“œ๋Š” 2.4.1์—์„œ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

        const spy = sandbox.spy();
        sandbox.stub(window, 'google').value({
            maps: {
                LatLng: x => x,
                Map: spy
            }
        });

๊ทธ๋Ÿฌ๋‚˜ 3.2.1์—์„œ๋Š” TypeError: Cannot stub non-existent own property google ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๊ฐ€์ด๋“œ์— ์–ธ๊ธ‰๋˜์–ด ์žˆ์ง€ ์•Š์œผ๋ฏ€๋กœ ํšŒ๊ท€๋กœ ๋ณด์ž…๋‹ˆ๋‹ค.

Bug Regression

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

~์ด ๋™์ž‘์„ ๋ณต์› ํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ~

์กด์žฌํ•˜์ง€ ์•Š๋Š” ์†์„ฑ ์Šคํ„ฐ ๋น™์„ ์ง€์›ํ•˜๋Š” ์‚ฌ์šฉ ์‚ฌ๋ก€๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค.

๋‚ด ์‚ฌ์šฉ ์‚ฌ๋ก€์—์„œ๋Š” ๊ตฌ์„ฑ ๊ฐœ์ฒด์˜ ์†์„ฑ์„ ์Šคํ„ฐ ๋น™ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. config ๊ฐœ์ฒด์—๋Š” ๋‹ค์–‘ํ•œ ์„ ํƒ์  ํ‚ค๊ฐ€ ์žˆ์œผ๋ฉฐ ๊ฐœ๋ฐœ์ž ์ปดํ“จํ„ฐ์—์„œ ํŒŒ์ผ์„๋กœ๋“œํ•˜์—ฌ ์ดˆ๊ธฐํ™”๋ฉ๋‹ˆ๋‹ค. ํŠน์ • ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•  ๋•Œ ์•Œ๋ ค์ง„ ๊ฐ’์œผ๋กœ ์„ค์ •๋œ ํ‚ค ์ค‘ ํ•˜๋‚˜๊ฐ€ ํ•„์š”ํ•˜๋ฉฐ ๊ฐœ๋ฐœ์ž์˜ ๊ฐœ์ฒด๋ฅผ์žˆ๋Š” ๊ทธ๋Œ€๋กœ ๋ณต์›ํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

sandbox.stub(serverSecrets, 'the_key_i_need_set').value(fakeValue) ๋Š”์ด๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๋งค์šฐ ๋ช…ํ™•ํ•œ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ๋Ÿฐํƒ€์ž„์— ํ‚ค๊ฐ€ ์„ค์ •๋˜์—ˆ๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ์•Œ์ง€ ๋ชปํ•˜๋”๋ผ๋„ ๋™์ผํ•œ ๋™์ž‘์„ ์–ป๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค _.

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

# 1512์™€ ๊ด€๋ จ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

์†์„ฑ์ด ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด ์ƒŒ๋“œ ๋ฐ•์Šค์— ์ถ”๊ฐ€ ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๋ฎ์–ด ์“ฐ๊ธฐ ๋งŒํ•˜๋ฉด๋ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์˜ˆ, ์ด์ „์— ํšจ๊ณผ๊ฐ€ ์žˆ์—ˆ๊ณ  ๋ณ€๊ฒฝํ•ด์•ผํ•œ๋‹ค๊ณ  ๋ช…์‹œ ์ ์œผ๋กœ ๋งํ•˜์ง€ ์•Š์•˜๋‹ค๋ฉด ํšŒ๊ท€์ž…๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ ๋ฌด์—‡์„ํ•ด์•ผํ•˜๋Š”์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ฐ’์„ ์Šคํ„ฐ ๋น™ํ•˜๋Š” ๊ฒƒ์ด ์˜๋ฏธ๊ฐ€์—†๊ณ  ์ง€์›๋˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ๋ฌธ์„œ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๊ฑฐ๋‚˜ ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋งŒ๋“œ์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?

์†์„ฑ์ด ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด ์ƒŒ๋“œ ๋ฐ•์Šค์— ์ถ”๊ฐ€ ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๋ฎ์–ด ์“ฐ๊ธฐ ๋งŒํ•˜๋ฉด๋ฉ๋‹ˆ๋‹ค.

์ƒŒ๋“œ ๋ฐ•์Šค์— ์†์„ฑ์„ ์ถ”๊ฐ€ ํ•  ๋•Œ ์ข‹์€ ์ ์€ sinon์ด sandbox.restore() ๋ฅผ ํ†ตํ•ด ๊ฐ ํ…Œ์ŠคํŠธ๊ฐ„์— ์ „์—ญ ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์„ ๊นจ๋—ํ•˜๊ฒŒ ์œ ์ง€ํ•˜๋Š” ๋ฐ ๋„์›€์ด๋œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํŠนํžˆ API๋ฅผ ์ œ์–ดํ•˜์ง€ ์•Š๋Š” Google Maps์™€ ๊ฐ™์€ ํƒ€์‚ฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋‹ค๋ฃฐ ๋•Œ ๋งค์šฐ ์œ ์šฉํ•œ ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค. 3.x ๋ผ์ธ์—์„œ ์ž‘๋™ํ•˜๋„๋ก ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค๋ฉด ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋˜ํ•œ ๋‚˜๋Š” ์™„์ „ํ•œ ์˜ˆ๋ฅผ ์ œ๊ณตํ•˜์ง€ ์•Š๋Š” ์ฃ„๋ฅผ ์ €์งˆ๋ €๋‹ค๋Š” ๊ฒƒ์„ ๊นจ๋‹ฌ์•˜์Šต๋‹ˆ๋‹ค. ๋‚ด ์ƒŒ๋“œ ๋ฐ•์Šค๋Š” 2.4.1 ํ˜•์‹์œผ๋กœ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

let sandbox;

before(() => { sandbox = sinon.sandbox.create(); })
afterEach(() => { sandbox.restore(); })

๊ทธ๊ฒƒ์ด ์ค‘์š”ํ•œ์ง€ ํ™•์‹คํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋” ๋นจ๋ฆฌ ์ œ๊ณตํ•˜์ง€ ์•Š์€ ๊ฒƒ์— ๋Œ€ํ•ด ์‚ฌ๊ณผ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

@ZebraFlesh๊ฐ€ ์„ค๋ช…ํ•˜๋Š” ์‹œ๋‚˜๋ฆฌ์˜ค์™€ ๊ฐ™์€ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ ํ…์ŠคํŠธ ๊ณ ์ • ์žฅ์น˜๋ฅผ ๋” ๋ช…์‹œ ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

// not so explicit, doesn't work with [email protected]
beforeEach(function() {
    const spy = sandbox.spy();
    sandbox.stub(window, 'google').value({
        maps: {
            LatLng: x => x,
            Map: spy
        }
    }); 
});
// more explicit, works with sinon<strong i="9">@2</strong>, sinon<strong i="10">@3</strong>
function setGoogleMapsFixture(sandbox) {
    window.google = {
        maps: {
            LatLng: x => x,
            Map: sandbox.spy()
        }
    };
}

function removeGoogleMapsFixture() {
    delete window.google;
}

beforeEach(function() {
    setGoogleMapsFixture(sandbox)
});

// not using afterEach, as this only needs to happen
// after the last test in this block is run
after(function() {
    removeGoogleMapsFixture();
});

์œ„์—์„œ ์„ค๋ช…ํ•œ ๊ฒƒ๊ณผ ๊ฐ™์ด ์กฐ๋ช…๊ธฐ๋ฅผ๋ณด๋‹ค ๋ช…์‹œ ์ ์œผ๋กœ ์„ค์ •ํ•˜๋ฉด ์กด์žฌํ•˜์ง€ ์•Š๋Š” ์ž์ฒด ์†์„ฑ์˜ ์Šคํ„ฐ ๋น™์„ ํ—ˆ์šฉํ•˜๋Š” Sinon์˜ ๊ธฐ๋Šฅ์ด ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ ๋ฌด์—‡์„ํ•ด์•ผํ•˜๋Š”์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ฐ’์„ ์Šคํ„ฐ ๋น™ํ•˜๋Š” ๊ฒƒ์ด ์˜๋ฏธ๊ฐ€์—†๊ณ  ์ง€์›๋˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ๋ฌธ์„œ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๊ฑฐ๋‚˜ ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋งŒ๋“œ์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?

(@ZebraFlesh์—์„œ ์„ค๋ช…ํ•œ ๊ฒƒ๊ณผ ๊ฐ™์€) ์ผ๋ถ€ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ ํŽธ๋ฆฌ ํ•  ์ˆ˜ โ€‹โ€‹์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์ง€๋งŒ ์กด์žฌํ•˜์ง€ ์•Š๋Š” ์ž์ฒด ์†์„ฑ์„ ์Šคํ„ฐ ๋น™ํ•˜๋Š” ๊ฒƒ์€ ํ…Œ์ŠคํŠธ์—์„œ ์‹ค์ˆ˜๋กœ ์ด์–ด์งˆ ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์Šคํ…ํ•˜๋ ค๋Š” ๊ธฐ์กด ์ž์‚ฐ. ์šฐ๋ฆฌ๋Š” ๋„ˆ๋ฌด ์ œํ•œ์ ์ด์ง€ ์•Š์œผ๋ฉด ์„œ ์‹ค์ˆ˜์˜ ๊ฐ€๋Šฅ์„ฑ์„ ์—†์• ๋Š” ๊ฒƒ์„ ๋ชฉํ‘œ๋กœํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

์กด์žฌํ•˜์ง€ ์•Š๋Š” ์ž์ฒด ์†์„ฑ์„ ์Šคํ„ฐ ๋น™ํ•˜๋Š” ๊ฒƒ์€ ์ง€์›๋˜์ง€ ์•Š์•„์•ผํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋ฌธ์„œ๋ฅผ ์—…๋ฐ์ดํŠธํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

@mroderick ๋ฒ„๊ทธ๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์—์„œ ๋™์˜ํ•˜์ง€๋งŒ ์ด๋ฏธ ์ผ๋ฐ˜ ์Šคํ…์— ๋Œ€ํ•ด์„œ๋Š”์ด๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋™์ž‘ ์ง€์›์„ ์ค‘๋‹จํ•ด์•ผํ•˜๋Š” ๊ฒฝ์šฐ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ํ•ด๋‹น ๋™์ž‘๋„ ์ œ๊ฑฐํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ์ƒŒ๋“œ ๋ฐ•์Šค๊ฐ€ ์ผ๋ฐ˜์ ์œผ๋กœ ๋ช‡ ๊ฐ€์ง€ ๊ฐ€๋Šฅ์„ฑ์„ _add_ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ƒŒ๋“œ ๋ฐ•์Šค ์™ธ๋ถ€์—์„œ๋งŒ์ด ๊ธฐ๋Šฅ์„ ์ง€์›ํ•˜๋Š” ๊ฒƒ์€ ์ด์ƒ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ง€์ง€๋Œ€๋ฅผ ์ œ๊ฑฐํ•˜๋Š” ๊ฒƒ์€ ํŒŒ๊ดด ๊ธฐ๋Šฅ์ด๋ฏ€๋กœ ํฐ ๋ฒ”ํ”„๋„ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ๋‹ค์Œ ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค.

  • ์ด ์ฐจ๋‹จ ๊ธฐ๋Šฅ์„ ์ˆ˜์ •ํ•˜๊ธฐ ์œ„ํ•ด ์ƒŒ๋“œ ๋ฐ•์Šค์— ๋Œ€ํ•œ ํ™•์ธ์„ ์ฆ‰์‹œ ์ œ๊ฑฐํ•˜์‹ญ์‹œ์˜ค.

๋˜๋Š” / ๋ฐ (?)

  • ์ผ๋ฐ˜ ๋ฐ ์ƒŒ๋“œ ๋ฐ•์Šค ์Šคํ…์— ๋Œ€ํ•œ ๊ธฐ๋Šฅ ์ œ๊ฑฐ

    • ์—…๋ฐ์ดํŠธ ๋œ ๋ฌธ์„œ๋กœ ์ƒˆ๋กœ์šด ์ฃผ์š” ๋ฒ„์ „ ์ถœ์‹œ

์œ„์—์„œ ์„ค๋ช…ํ•œ ๊ฒƒ๊ณผ ๊ฐ™์ด ์กฐ๋ช…๊ธฐ๋ฅผ๋ณด๋‹ค ๋ช…์‹œ ์ ์œผ๋กœ ์„ค์ •ํ•˜๋ฉด ์กด์žฌํ•˜์ง€ ์•Š๋Š” ์ž์ฒด ์†์„ฑ์˜ ์Šคํ„ฐ ๋น™์„ ํ—ˆ์šฉํ•˜๋Š” Sinon์˜ ๊ธฐ๋Šฅ์ด ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋‹น์‹ ์˜ ์กฐ๋ช…๊ธฐ๊ฐ€ ๋‹น์‹ ์˜ ํ…Œ์ŠคํŠธ ์‚ฌ์ด์— ๊ฒฐ์ฝ” ๋ณ€ํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ์ž˜ ์ž‘๋™ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‚ด ๋น„ํ’ˆ์€ ๊ทธ๋ ‡์Šต๋‹ˆ๋‹ค. ๊ฐ„๋‹จํ•œ ์˜ˆ๋Š” ์„ฑ๊ณต ๋ฐ ์‹คํŒจ ์‚ฌ๋ก€๋ฅผ ๋ชจ๋‘ ๋‹ค๋ฃจ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

it('handles the success case', () => {
        const spy = sandbox.spy();
        sandbox.stub(window, 'google').value({
            maps: {
                LatLng: x => x,
                Map: spy
            }
        });
        // ... test, including asserting that the spy was called
});

it('handles the failure case', () => {
        const msg = 'test error';
        sandbox.stub(window, 'google').value({
            maps: {
                LatLng: x => x,
                Map: sandbox.stub().throws(new Error(msg))
            }
        });
        // ... test, ignoring spy calls and instead focusing on error handling
});

2.x์˜ ๋™์ž‘์€ sandbox.restore() ๋ฅผ ํ†ตํ•ด ๊ฐ ํ…Œ์ŠคํŠธ ํ›„ ๋ชจ๋“  ๊ฒƒ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ •๋ฆฌ๋œ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์œ„์— ์„ค๋ช… ๋œ๋ณด๋‹ค ๋ช…์‹œ์ ์ธ ์กฐ๋ช…๊ธฐ ์„ค์ • ์˜ˆ์ œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋™์ผํ•œ ํšจ๊ณผ๋ฅผ ์–ป๊ธฐ ์œ„ํ•ด afterEach ํ›„ํฌ์—์„œ ์†Œ์œ ํ•˜์ง€ ์•Š์€ ์†์„ฑ์„ ์‚ญ์ œํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค.

์‹ค์ˆ˜๋กœ ๊ธฐ์กด ์†์„ฑ์˜ ์ด๋ฆ„์„ ์ž…๋ ฅํ•˜์—ฌ ์ž ์žฌ์  ์ธ ์‹ค์ˆ˜๋ฅผ ์œ ๋ฐœํ•˜๋Š” ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด sinon์€ ๊ณต์šฉ API๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • stub.ownValue() : ์ž์‹ ์˜ ์†์„ฑ ๋งŒ ์Šคํ…, ์†Œ์œ ํ•˜์ง€ ์•Š์€ ์†์„ฑ์— ๋Œ€ํ•ด ๋ฐœ์ƒ
  • stub.value() : ์†Œ์œ ํ•˜์ง€ ์•Š์€ ์†์„ฑ ๋งŒ ์Šคํ…ํ•˜๊ณ  ์ž์‹ ์˜ ์†์„ฑ์— ๋Œ€ํ•ด throwํ•ฉ๋‹ˆ๋‹ค.

API๊ฐ€ ๋”์šฑ ๋ช…ํ™• ํ•ด์ง€๊ณ  ์†Œ๋น„์ž๋Š” ๋‹น๋ฉดํ•œ ์ž‘์—…์— ์ ํ•ฉํ•œ ๋„๊ตฌ๋ฅผ ์„ ํƒํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

@lucasfcosta๋Š” ๋ฐ˜๋Œ€ ๊ฒฌํ•ด๋ฅผ ๊ฐ€์ง€๊ณ  ์‹œ๊ฐ„ (์ •์ƒ ์Šคํ… ๋‹ค๋ฃจ๊ณ  ์žˆ์ง€๋งŒ) ์ด๊ฒƒ์€ ๋งค์šฐ # 1508์—์„œ ํ† ๋ก  ๊ด€๋ จ์ด์žˆ๋‹ค - ์šฐ๋ฆฌ๊ฐ€ํ•˜์ง€ ์•Š๋Š” throw_ _should์ด undefined ์†์„ฑ. ์šฐ๋ฆฌ๊ฐ€ ๋ฌด์—‡์— ์ฐฉ์ˆ˜ํ•˜๋“ , ๋‚˜๋Š” ์ผ๋ฐ˜ ์Šคํ…๊ณผ ์ƒŒ๋“œ ๋ฐ•์Šค๋ฅผ์œ„ํ•œ ์Šคํ„ฐ ๋น™ API์—์„œ _ ์ผ๊ด€ ์ ์ด์–ด์•ผํ•œ๋‹ค๊ณ  ๋ฏฟ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ํ•œ ๊ฒฝ์šฐ์—๋งŒ ์ง€์›ํ•ด์„œ๋Š” ์•ˆ๋˜๋ฉฐ ๋‹ค๋ฅธ ๊ฒฝ์šฐ์—๋Š” ์ง€์›ํ•˜์ง€ ์•Š์•„์•ผํ•ฉ๋‹ˆ๋‹ค.

ํ˜„์žฌ ์ƒํ™ฉ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • 1.x๋ฅผ ๋˜์ง€๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” ์ผ๋ฐ˜ ์Šคํ…์ด 2.0์—์„œ ๋ณ€๊ฒฝ๋˜์—ˆ์œผ๋ฉฐ ๋” ์ด์ƒ ๋˜์ง€์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • ์ƒŒ๋“œ ๋ฐ•์Šค๋Š” ๋˜์ง€๋Š” ๋ฐ ์‚ฌ์šฉ๋˜์ง€ ์•Š์•˜์ง€๋งŒ 3.1 (?)์—์„œ ๋˜์ง€๊ธฐ ์‹œ์ž‘ํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ์ž ์‹œ ๋™์•ˆ ๊ธฐ๋Šฅ ํŒจ๋ฆฌํ‹ฐ๊ฐ€ ์žˆ์—ˆ์ง€๋งŒ ๋‹ค์‹œ ์žƒ์–ด ๋ฒ„๋ ธ์Šต๋‹ˆ๋‹ค.์ด ์ง€๊ทธ์žฌ๊ทธ๊ฐ€ ์‚ฌ์šฉ์ž์—๊ฒŒ๋ณ„๋กœ ์œ ์ตํ•˜์ง€ ์•Š๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋ฏ€๋กœ์ด ๋…ผ์˜๋ฅผ ์‹œ์ž‘ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ์ข€ ๋” ๊ตฌ์ฒด์ ์ธ ํ…Œ์ŠคํŠธ๋ฅผ ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์—์„œ Morgan๊ณผ ๋™์˜ํ•˜์ง€๋งŒ ๋‘ ๊ฐ€์ง€ ์ฃผ์š” ๋ฆด๋ฆฌ์Šค์— ๋Œ€ํ•œ ๋™์ž‘์„ ์‚ญ์ œ ํ•œ ๋‹ค์Œ ๋‹ค์‹œ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์„ ์ข‹์•„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด ํšŒ๊ท€๋ฅผ ๋˜๋Œ๋ฆฌ๋ ค๋ฉด ์ตœ์†Œํ•œ์˜ ์†Œ์Œ (๊ณ ๊ฐ์— ๋Œ€ํ•œ ์ˆ˜์ •,์ด ์ถ”์ ๊ธฐ์˜ ์งˆ๋ฌธ / ๋ฌธ์ œ)์„ ๋งŒ๋“ค ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๋ถˆํŽธ ํ•จ์„ ์ดํ•ดํ•˜์ง€๋งŒ ์ตœ์†Œํ•œ์˜ ์ฝ”๋“œ ๋ณ€๊ฒฝ์œผ๋กœ ์‰ฌ์šด ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์ด์žˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

before(function() {
  window.google = 'This is a placeholder for sinon to overwrite.';
});

after(function() {
  delete window.google;
});

์ด๋ฅผ ํ†ตํ•ด sinon ์ฝ”๋“œ๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์€ ์ƒํƒœ๋กœ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค.

ํšŒ๊ท€ vs ๋ถˆ๋Ÿ‰ ๋ฌธ์„œ

ํ…Œ์ŠคํŠธ๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์˜ˆ์ƒ๋˜๋Š” ๋™์ž‘ ์ธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ œ ์ƒ๊ฐ์— ๊ทธ๊ฒƒ์„ ๋ฐ˜์˜ํ•˜๊ธฐ ์œ„ํ•ด ๋ฌธ์„œ๋ฅผ ์—…๋ฐ์ดํŠธํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ์ฃผ์š” ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ํ—ˆ์šฉ๋ฉ๋‹ˆ๋‹ค.

@fearphage ํ˜„์ƒ ์œ ์ง€๋Š” ์กด์žฌํ•˜์ง€ ์•Š๋Š” ํ•„๋“œ๋ฅผ

ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€ # 1557์—์„œ ๊ตฌํ˜„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์–‘ํ•œ ์Šค๋ ˆ๋“œ๋ฅผ ์ฝ์—ˆ์œผ๋ฉฐ ์™œ ์ด๋Ÿฐ ์ผ์ด ๋ฐœ์ƒํ–ˆ๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ์ง€๋งŒ ํด๋ž˜์Šค ํ”„๋กœํ†  ํƒ€์ž…์—์„œ ๊ตฌํ˜„๋˜๋Š” ํ•จ์ˆ˜๋ฅผ ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” Typescript์—์„œ๋Š” ์ •๋ง ๊ณ ํ†ต ์Šค๋Ÿฝ์Šต๋‹ˆ๋‹ค.์ด ๊ฒฝ์šฐ ๋ชจ๋“  ๊ฒƒ์ด ๊ดœ์ฐฎ์•„ ๋ณด์ด์ง€๋งŒ sinon์ด ๋”๋ฏธ๋ฅผ ๋ฑ‰์–ด๋ƒ…๋‹ˆ๋‹ค. ํ˜„๋ช…ํ•ฉ๋‹ˆ๋‹ค ( keyof YourType ๋Š” ํ”„๋กœํ†  ํƒ€์ž… ์ฒด์ธ ์•„๋ž˜์— ์ •์˜ ๋œ ๋ชจ๋“  ๊ณต์šฉ ํ•จ์ˆ˜๋ฅผ ๊ธฐ๊บผ์ด ํ—ˆ์šฉํ•˜๋ฏ€๋กœ).

๋‚˜๋Š” Typescript๊ฐ€ ์•„๋งˆ๋„ ๋‹น์‹ ๋“ค์—๊ฒŒ ์šฐ์„  ์ˆœ์œ„๊ฐ€ ์•„๋‹ˆ๋ผ๋Š” ๊ฒƒ์„ ์•Œ์ง€๋งŒ JS์—์„œ๋„ myObject.callMe() ๋Š” ์™„๋ฒฝํ•˜๊ฒŒ ํ–‰๋ณตํ•˜๊ฒŒ ์‹คํ–‰๋˜๋Š” ๋ฐ˜๋ฉด sinon.stub(myObject, "callMe") ๋Š” ๊ทธ๋ ‡์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ๊ฒƒ์„ ์Šคํ„ฐ๋ธŒํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ๊ธฐ ์œ„ํ•ด ํŠน์ • ๊ฐ์ฒด๊ฐ€ ์–ด๋–ป๊ฒŒ ๊ฒฐํ•ฉ๋˜์—ˆ๋Š”์ง€ ์กฐ์‚ฌํ•˜์ง€ ์•Š๊ณ  ์‹ถ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

ํด๋ž˜์Šค๊ฐ€ JS์—์„œ ๋” ๋งŽ์€ ๊ธฐ๋ณธ ์ง€์›์„ ๋ฐ›๊ณ  ์žˆ๋‹ค๋Š” ์ ์„ ๊ณ ๋ คํ•  ๋•Œ ์ด๊ฒƒ์ด ํ–‰๋ณตํ•œ ๊ฒฝ๋กœ๋ฅผ ๋งŒ๋“œ๋Š” ์ค‘์š”ํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๋ฉ”์„œ๋“œ๊ฐ€ ๊ฐ์ฒด์— ์ •์˜๋˜์–ด ์žˆ์ง€ ์•Š๋‹ค๋Š” ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์˜ค๋ฅ˜๊ฐ€ ํ”„๋กœํ†  ํƒ€์ž…์—์žˆ์„ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ myObject.callMe = sinon.stub(); ์‚ฌ์šฉํ•˜์—ฌ ๊ฐœ์ฒด๋ฅผ ์ง์ ‘ ์ˆ˜์ •ํ•˜๋Š” ๊ฒƒ์€ ๊ทธ๋ ‡๊ฒŒ ๋ฒˆ๊ฑฐ๋กญ์ง€ ์•Š์€ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. IMHO ... ๋˜ํ•œ ํ”„๋กœํ†  ํƒ€์ž…์ด ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— ์ •๋ฆฌ / ํ•ด์ฒด ๊ธฐ๋Šฅ์„ ๋งŒ๋“ค์ง€ ์•Š์•„๋„๋ฉ๋‹ˆ๋‹ค.

๋„ค, ํ•ด๊ฒฐํ•˜๊ธฐ๊ฐ€ ๊ทธ๋ฆฌ ์–ด๋ ต์ง€ ์•Š์€ ๊ฒƒ ๊ฐ™์•„์š”. ์‚ฌ๋ฌผ์ด ์–ด๋–ป๊ฒŒ ๊ตฌํ˜„๋˜๋Š”์ง€ ์•Œ๊ธฐ ์œ„ํ•ด ๋‚˜์—๊ฒŒ ๋” ๋งŽ์€์ธ์ง€ ๋ถ€ํ•˜๋ฅผ ๊ฐ€ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์˜€๊ธฐ ๋•Œ๋ฌธ์— ๋™์ผํ•œ ๊ฐ์ฒด์— ๋Œ€ํ•ด ์—ฐ์† ๋œ ๋‘ ์ค„์˜ ์Šคํ„ฐ ๋น™ ์ฝ”๋“œ๊ฐ€ ๋‹ค๋ฅธ ์ด์œ ์™€ ๋ถ„ํ•ด์—์„œ ์Šคํ„ฐ๋ธŒ ์ค‘ ํ•˜๋‚˜๋ฅผ ์ˆ˜๋™์œผ๋กœ ์‚ญ์ œํ•˜๋Š” ์ด์œ ๋ฅผ ์„ค๋ช…ํ•˜๊ธฐ ์œ„ํ•ด ํ…Œ์ŠคํŠธ์— ์ฃผ์„์„ ์ถ”๊ฐ€ํ•ด์•ผํ•œ๋‹ค๊ณ  ๋Š๊ผˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋‹ค๋ฅธ ํ•˜๋‚˜๋Š” ์ƒŒ๋“œ ๋ฐ•์Šค์—์„œ ์ฒ˜๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค.

~์ด ๋™์ž‘์„ ๋ณต์› ํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ~

์กด์žฌํ•˜์ง€ ์•Š๋Š” ์†์„ฑ ์Šคํ„ฐ ๋น™์„ ์ง€์›ํ•˜๋Š” ์‚ฌ์šฉ ์‚ฌ๋ก€๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค.

๋‚ด ์‚ฌ์šฉ ์‚ฌ๋ก€์—์„œ๋Š” ๊ตฌ์„ฑ ๊ฐœ์ฒด์˜ ์†์„ฑ์„ ์Šคํ„ฐ ๋น™ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. config ๊ฐœ์ฒด์—๋Š” ๋‹ค์–‘ํ•œ ์„ ํƒ์  ํ‚ค๊ฐ€ ์žˆ์œผ๋ฉฐ ๊ฐœ๋ฐœ์ž ์ปดํ“จํ„ฐ์—์„œ ํŒŒ์ผ์„๋กœ๋“œํ•˜์—ฌ ์ดˆ๊ธฐํ™”๋ฉ๋‹ˆ๋‹ค. ํŠน์ • ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•  ๋•Œ ์•Œ๋ ค์ง„ ๊ฐ’์œผ๋กœ ์„ค์ •๋œ ํ‚ค ์ค‘ ํ•˜๋‚˜๊ฐ€ ํ•„์š”ํ•˜๋ฉฐ ๊ฐœ๋ฐœ์ž์˜ ๊ฐœ์ฒด๋ฅผ์žˆ๋Š” ๊ทธ๋Œ€๋กœ ๋ณต์›ํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

sandbox.stub(serverSecrets, 'the_key_i_need_set').value(fakeValue) ๋Š”์ด๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๋งค์šฐ ๋ช…ํ™•ํ•œ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ๋Ÿฐํƒ€์ž„์— ํ‚ค๊ฐ€ ์„ค์ •๋˜์—ˆ๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ์•Œ์ง€ ๋ชปํ•˜๋”๋ผ๋„ ๋™์ผํ•œ ๋™์ž‘์„ ์–ป๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค _.

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