JavaScript Testing Tool - Jest

LeeJangHeeยท2018๋…„ 11์›” 11์ผ
16
post-thumbnail

๐Ÿฃ What is the Jest?

Jest๋ž€ ํŽ˜์ด์Šค๋ถ์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๋ฆฌ์•กํŠธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ํฌํ•จํ•œ ๋ชจ๋“  ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ…Œ์ŠคํŠธ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค. Jest์˜ ์ฒ ํ•™ ์ค‘ ํ•˜๋‚˜๋Š” "Zero-configuration", ์„ค์ • ์—†๋Š” ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์„ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๋“ค์€ ๊ฐœ๋ฐœ์ž์—๊ฒŒ ์‚ฌ์šฉ ์ค€๋น„๊ฐ€ ๋œ ๋„๊ตฌ๊ฐ€ ์ฃผ์–ด์งˆ ๋•Œ, ๊ฐœ๋ฐœ์ž๊ฐ€ ๋ณด๋‹ค ๋งŽ์€ test๋ฅผ ์ž‘์„ฑํ•œ๋‹ค๊ณ  ๋งํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด๋Ÿฐ ํ…Œ์ŠคํŠธ๋Š” ๋ณด๋‹ค ์•ˆ์ •์ ์ด๊ณ  ๊ฑด๊ฐ•ํ•œ ์ฝ”๋“œ์˜ ๊ฒฐ๊ณผ๋กœ ๋Œ์•„์˜ต๋‹ˆ๋‹ค.

๐Ÿฅ How to install Jest?

Jest๋Š” Zero-Configuration์ด๋ผ๋Š” ๋‹จ์–ด์— ๊ฑธ๋งž๊ฒŒ yarn ์ด๋‚˜ npm ์œผ๋กœ ์„ค์น˜๋งŒ ํ•˜๋ฉด ๋์ž…๋‹ˆ๋‹ค.

  • yarn ์„ ์ด์šฉํ•œ ์„ค์น˜
    yarn add --dev jest
  • npm ์„ ์ด์šฉํ•œ ์„ค์น˜
    npm install --save-dev jest

๐Ÿ” How to use Jest?

Jest๋Š” ์—ฌ๋Ÿฌ๊ฐ€์ง€ ํƒ€์ž…์˜ ํ…Œ์ŠคํŠธ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

  • Common Matchers
    test('adds 1 + 2 to equal 3', () => {
        expect(sum(1, 2)).toBe(3);
    });
    
    test('object assignment', () => {
        const data = { one: 1};
        data['two'] = 2;
        expect(data).toEqual({one: 1, two: 2});
    });
    
    test('adding positive numbers is not zero', () => {
        for (let a = 1; a < 10; a++) {
            for (let b = 1; b < 10; b++) {
                expect(a + b).not.toBe(0);
            }
        }
    });
  • Truthiness
    • ์ฐธ, ๊ฑฐ์ง“ ํ…Œ์ŠคํŠธ์—์„œ๋Š” ๋•Œ๋•Œ๋กœ undefined, null, false๋ฅผ ๊ตฌ๋ณ„ํ•ด ์ค˜์•ผ ํ•  ๋•Œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
    • ํ•˜์ง€๋งŒ ์‚ฌ์šฉ์ž๊ฐ€ ์ด๊ฒƒ์˜ ๊ตฌ๋ณ„์„ ์›ํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ๊ทธ์— ๋”ฐ๋ฅธ ๊ธฐ๋Šฅ๋„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
    test('null', () => {
        const n = null;
        expect(n).toBeNull();           // only null
        expect(n).toBeUndefined();      // only undefined 
        expect(n).not.toBeUndefined();  // opposite of toBeUndefined
        expect(n).not.toBeTruthy();     // Anything that an if statement treats as true  
        expect(n).toBeFalsy();          // Anything that an if statement treats as false 
    });
    
    test('zero', () => {
        const z = 0;
        expect(z).not.toBeNull();
        expect(z).toBeDefined();
        expect(z).not.toBeUndefined();
        expect(z).not.toBeTruthy();
        expect(z).toBeFalsy();
    });
  • Number
    test('two plus two', () => {
        const value = 2 + 2;
        expect(value).toBeGreaterThan(3);
        expect(value).toBeGreaterThanOrEqual(3.5);
        expect(value).toBeLessThan(5);
        expect(value).toBeLessThanOrEqual(4.5);
    
        expect(value).toBe(4);
        expect(value).toEqual(4);
    });
    
    // float๊ฐ’ ํ…Œ์ŠคํŠธ ์‹œ, toEqual ๋Œ€์‹ ์— toBeCloseTo๋ฅผ ์‚ฌ์šฉํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.
    // toEqual ์‚ฌ์šฉ์‹œ ๋ฏธ์„ธํ•˜๊ฒŒ ๊ฐ’์ด ๋‹ค๋ฅด๊ฒŒ ๋‚˜์˜ฌ ์ˆ˜ ์žˆ์–ด ํ…Œ์ŠคํŠธ๊ฐ€ ํ‹€๋ฆด์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.
    
    test('adding floating point numbers', () => {
        const value = 0.1 + 0.2;
        expect(value).toBeCloseTo(0.3);
    });
    
    // Strings
    test('there is no I in team', () => {
        expect('team').not.toMatch(/I/);
    });
    
    test('but there is a "stop" in Christoph', () => {
        expect('Christoph').toMatch(/stop/);
    });
  • Array
    const shoppingList = [
        'diapers',
        'kleenex',
        'trash bags',
        'paper towels',
        'beer'
    ];
    
    test('the shopping list has beer on it', () => {
        expect(shoppingList).toContain('beer');
    });

๐Ÿ— Unit Test Example

Jest๋ฅผ ์‚ฌ์šฉํ•ด๋ณด๊ธฐ ์œ„ํ•ด ๊ฐ„๋‹จํ•œ ๋กœ๋˜๋ฒˆํ˜ธ ์ƒ์„ฑ๊ธฐ๋ฅผ ๋งŒ๋“ค์–ด ๋ณด์•˜์Šต๋‹ˆ๋‹ค.

  • ์š”๊ตฌ์‚ฌํ•ญ

    • ๋ˆ์„ ์ž…๋ ฅํ•˜๋ฉด ๊ธˆ์•ก์— ๋งž๋Š” ๋กœ๋˜ ๋ฒˆํ˜ธ๋“ค์ด ์ž๋™์œผ๋กœ ์ƒ์„ฑ๋˜์–ด ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค.
  • Host code

    const myLottos = shop.buyTicket('5000');
    
    console.log(myLottos.showTickets());
    /*
    [
    	[ 10, 2, 15, 28, 26, 8 ],
      [ 16, 45, 17, 20, 30, 29 ],
      [ 31, 15, 4, 28, 42, 35 ],
      [ 5, 34, 35, 22, 20, 40 ],
      [ 5, 13, 25, 38, 20, 8 ] 
    ]
    */
  • lotto.spec.js
    test('buy ticket at shop', () => {
        const ticket = shop.buyTicket(5000);
        expect(ticket.showTickets().length).toBe(5);
    });
    
    test('create random Lotto numbers ', () => {
    	expect(shop.createRandomNumbers().length).toBe(6);
    });
  • lotto.js
    const lotto = (function() {
        const numbers = Symbol('numbers');
        return ({
        [numbers]: [],
        inputNumbers(inputNumbers) {
            this[numbers] = inputNumbers;
        },
        create: function (inputNumbers) {
            const lotto = Object.assign({}, this);
            lotto.inputNumbers(inputNumbers);
            return lotto;
        },
        showNumber() {
            return this[numbers];
        }
    });
    })();
    
    const shop = ( function () {
        const lottos = Symbol('lottos');
        return ({
        [lottos]: [],
        buyTicket(money) {
            if(money < 1000) {
                throw Error('1000์› ์ด์ƒ์˜ ๊ธˆ์•ก๋งŒ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.');
            }
            const count = money / 1000;
            for(let i=0; i<count; i++) {
                this[lottos].push(lotto.create(this.createRandomNumbers()));
            }
        },
        createRandomNumbers() {
            const numbers = [];
            for(let i=1; i<=45; i++) {
                numbers.push(i);
            }
            numbers.sort(()=> Math.random() - 0.5);
            return numbers.slice(0,7);
        },
        showTickets() {
            console.log(this[lottos].map( a => a.showNumber() ));
            return this[lottos];
        }
    });
    })();
    
    module.exports = { lotto, shop };

๐Ÿ’ฉ ์ด ๊ธ€์„ ๋งˆ์น˜๋ฉฐ...

์•„์ง Jest๋ฅผ Unit test๋กœ ๋ฐ–์— ์‚ฌ์šฉํ•˜์ง€ ๋ชปํ•˜์˜€์ง€๋งŒ Jest์—๋Š” Snapshot์ด๋ผ๋Š” ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜์—ฌ React UI Test๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ ๊ธ€์—๋Š” ์ด UI test์™€ ๊ด€๋ จ๋œ ์˜ˆ์ œ๋กœ ๊ธ€์„ ์ค€๋น„ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

profile
Frontend Developer

8๊ฐœ์˜ ๋Œ“๊ธ€

comment-user-thumbnail
2018๋…„ 11์›” 11์ผ

์œ ์šฉํ•œ ๊ธ€์ด๋„ค์š”!

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ
comment-user-thumbnail
2018๋…„ 11์›” 11์ผ

์ข‹์€ ํฌ์ŠคํŠธ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค :>

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ
comment-user-thumbnail
2018๋…„ 11์›” 11์ผ

์ด๋ฒˆ ๊ธ€๋„ ์ž˜ ๋ดค์Šต๋‹ˆ๋‹ค. ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ
comment-user-thumbnail
2018๋…„ 11์›” 13์ผ

์ข‹์€ ๊ธ€ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ
comment-user-thumbnail
2018๋…„ 11์›” 14์ผ

์•„ ํ…Œ์ŠคํŒ… ๊ด€๋ จํ•ด์„œ ๊ณต๋ถ€์ข€ ํ•˜๋ ค ํ•˜๋Š”๋ฐ, ๋งˆ์นจ ์‹ค์Šตํ•˜๊ธฐ ์ข‹์€ ์ž๋ฃŒ๋„ค์š”!
๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ
comment-user-thumbnail
2018๋…„ 11์›” 22์ผ

์ข‹์€ ํฌ์ŠคํŠธ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค *)

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ
comment-user-thumbnail
2019๋…„ 2์›” 9์ผ

์ข‹์€ ๊ธ€ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค:)

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ
comment-user-thumbnail
2019๋…„ 4์›” 1์ผ

์ž˜ ๋ณด์•˜์Šต๋‹ˆ๋‹ค.
const myLottos = shop.buyTicket('5000');
buyTicket(money) {
return this;
},

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ