๐Ÿฃ 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 };

image.png

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

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