nuuco / test-tutorial

๐Ÿงช TDD : ๋ฆฌ์•กํŠธ์—์„œ test ์ž‘์„ฑํ•ด๋ณด๊ธฐ

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

TDD (Test-driven Development) in React

๐Ÿ“Œ TDD

์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ธฐ ์ „์— ํ…Œ์ŠคํŠธ๋ฅผ ์“ฐ๋Š” ์†Œํ”„ํŠธ์›จ์–ด ๊ฐœ๋ฐœ ๋ฐฉ๋ฒ•๋ก 

  • ์ž‘์€ ๋‹จ์œ„์˜ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋ฅผ ์ž‘์„ฑํ•˜๊ณ , ์ด๋ฅผ ํ†ต๊ณผํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ณผ์ •์„ ๋ฐ˜๋ณตํ•˜๋Š” ๊ฒƒ

  • ์ด 3๋‹จ๊ณ„๋กœ ์ด๋ฃจ์–ด์ง„๋‹ค.

    TDD 3๋‹จ๊ณ„

    โ€ป 1์˜ ๊ณผ์ •์„ ๋งˆ์น˜๊ธฐ ์ „๊นŒ์ง€ 2 ์ž‘์—…์„ ์‹œ์ž‘ํ•˜๋ฉด ์•ˆ๋œ๋‹ค!

    1. Write Failing Test: ์‹คํŒจํ•˜๋Š” ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ๋จผ์ € ์ž‘์„ฑํ•œ๋‹ค.
    2. Make Test Pass: ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์„ฑ๊ณต์‹œํ‚ค๊ธฐ ์œ„ํ•œ ์‹ค์ œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•œ๋‹ค. (ํ…Œ์ŠคํŠธ๋ฅผ ํ†ต๊ณผํ•  ์ •๋„์˜ ์ตœ์†Œ ์ฝ”๋“œ๋งŒ ์ž‘์„ฑ)
    3. Refactor: ์ค‘๋ณต ์ฝ”๋“œ ์ œ๊ฑฐ, ์ผ๋ฐ˜ํ™” ๋“ฑ์˜ ๋ฆฌํŒฉํ† ๋ง์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

  • TDD๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ 

    โ‡’ ์˜ˆ์ƒ์น˜ ๋ชปํ–ˆ๋˜ ๋ฒ„๊ทธ๋ฅผ ์ค„์—ฌ ์†Œ์š” ์‹œ๊ฐ„์„ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค! ์ฒ˜์Œ์—” ์†๋„๊ฐ€ ๋Š๋ฆฌ๋‹ค๊ณ  ๋Š๋‚„ ์ˆ˜ ์žˆ์œผ๋‚˜ ์žฅ๊ธฐ์ ์œผ๋กœ ๋ณด๋ฉด ์ฒ˜์Œ๋ถ€ํ„ฐ ๋ฒ„๊ทธ๋ฅผ ์ค„์—ฌ๊ฐ€๋ฉฐ ๊ฐœ๋ฐœํ•˜๋Š” ๊ฒƒ์ด ํšจ์œจ์ ์ด๋‹ค.

๐Ÿ“Œ Testing Library, Jest - ๋ฆฌ์•กํŠธ์—์„œ ํ…Œ์ŠคํŠธ ํ•˜๊ธฐ

  • Testing Library, Jest ๋‘˜๋‹ค React์—์„œ๋งŒ ์“ธ ์ˆ˜ ์žˆ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ์•„๋‹ˆ๋‹ค.

  • Testing Libarary์™€ Jest๋Š” ์—ญํ• ์ด ๊ฐ๊ฐ ๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ์— React์— ๋Œ€ํ•œ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•  ๋•Œ๋Š” ์–ด๋Š ํ•œ์ชฝ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ด์šฉํ•˜๋Š” ๊ฒƒ๋งŒ์œผ๋กœ๋Š” ํ…Œ์ŠคํŠธ๋ฅผ ํ•  ์ˆ˜ ์—†๋‹ค.

    โ‡’ ๋‘˜ ๋‹ค ์‚ฌ์šฉ!

๐Ÿงฉ Testing Library

  • Testing Library๋Š” ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ์‹ถ์€ ์ปดํฌ๋„ŒํŠธ๋‚˜ ํด๋ฆญ ์ด๋ฒคํŠธ๋“ฑ ๋‹ค์–‘ํ•œ ๊ณณ์— ์“ธ ์ˆ˜ ์žˆ๋‹ค.
  • Testing Libarary์—์„œ React์šฉ React Testing Library์„ ์ œ๊ณตํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, create-react-app์„ ์ด์šฉํ•˜์—ฌ React ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•˜๋ฉด ์ž๋™์œผ๋กœ Testing Libarary๋ฅผ ์ด์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿงฉ Jest

  • Jest๋Š” JavaScript์˜ Testing Framework / Test Runner๋กœ์จ, ํ…Œ์ŠคํŠธ ํŒŒ์ผ์„ ์ž๋™์œผ๋กœ ์ฐพ์•„ ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•˜๊ณ , ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•œ ๊ฒฐ๊ณผ ๊ธฐ๋Œ€๋งŒํผ ์˜ฌ๋ฐ”๋ฅธ ๊ฐ’์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š”์ง€ ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•˜์—ฌ ์ฒดํฌํ•˜์—ฌ ํ…Œ์ŠคํŠธ๊ฐ€ ์„ฑ๊ณต์ธ์ง€ ์‹คํŒจ์ธ์ง€๋ฅผ ํŒ๋‹จํ•ด ์ค€๋‹ค.

  • Jest ์—์„œ๋„ Mocha(Node.js ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ) ์ฒ˜๋Ÿผ it, test, describe ๋ฉ”์„œ๋“œ๋ฅผ ๋˜‘๊ฐ™์ด ์‚ฌ์šฉํ•œ๋‹ค.

    describe('๊ฐ„๋‹จํ•œ ํ…Œ์ŠคํŠธ', () => {
        test('2๋”ํ•˜๊ธฐ 2๋Š” 4', () => {
            expect(2 + 2).toBe(4);
        });
    
        it('2 ๋นผ๊ธฐ 1์€ 1', () => {
            expect(2 - 1).toBe(1);
        })
        
    })
    
    //test ํ•จ์ˆ˜์™€ it ํ•จ์ˆ˜๋Š” ์—ญํ• ์ด ๊ฐ™๋‹ค.
    //describe ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด it ์ด๋‚˜ test ํ•จ์ˆ˜๋ฅผ ํ•˜๋‚˜ ํŒŒ์ผ์— ์—ฌ๋Ÿฌ ๊ฐœ ํฌํ•จํ•  ์ˆ˜ ์žˆ๋‹ค.
    //describe ํ•จ์ˆ˜ ๋ธ”๋ก์€ Test Suites ๋ผ๊ณ  ๋ถˆ๋ฆฐ๋‹ค. 
    //test/it ํ•จ์ˆ˜ ๋ธ”๋ก์€ Test(TestCase) ๋ผ๊ณ  ๋ถˆ๋ฆฐ๋‹ค.
    //toBe() : expect ํ•จ์ˆ˜์—์„œ ์ง€์ •ํ•œ ๊ฐ’์ด toBe ํ•จ์ˆ˜์— ์ง€์ •ํ•œ ๊ฐ’๊ณผ ์ผ์น˜ํ•˜๋Š”์ง€ ์ฒดํฌ.

    ํ…Œ์ŠคํŠธ ์‹คํ–‰ ๊ฒฐ๊ณผ

๐Ÿงฉ ํ…Œ์ŠคํŠธ ์˜ˆ์‹œ๋“ค

  • App.test.js ๊ธฐ๋ณธ ํŒŒ์ผ ํ…Œ์ŠคํŠธ

    import { render, screen } from '@testing-library/react';
    import App from './App';
    
    test('renders learn react link', () => {
      render(<App />);
      const linkElement = screen.getByText(/TEST/i);
      expect(linkElement).toBeInTheDocument();
    });
    
    //test() : Jest ํ•จ์ˆ˜๋กœ ํ…Œ์ŠคํŠธ๊ฐ€ ์‹คํ–‰ํ•  ๋•Œ ๋ฐ˜๋“œ์‹œ ์ด์šฉํ•˜๋Š” ํ•จ์ˆ˜
    //   - ์ฒซ ๋ฒˆ์งธ ์ธ์ž : ํ…Œ์ŠคํŠธ๊ฐ€ ์–ด๋–ค ๋‚ด์šฉ์ธ์ง€, ํ…Œ์ŠคํŠธ ์„ค๋ช…
    //   - ๋‘ ๋ฒˆ์งธ ์ธ์ž : ํ•˜์ž๊ณ ํ•˜๋Š” ํ…Œ์ŠคํŠธ๋ฅผ ํ•จ์ˆ˜ ํ˜•ํƒœ๋กœ ๋„ฃ๋Š”๋‹ค.
    //
    // 1. ์ฒซ๋ฒˆ์งธ ์ค„์„ ๋ณด๋ฉด, ํ…Œ์ŠคํŠธํ•˜๊ณ ์ž ํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ render()ํ•จ์ˆ˜๋กœ ์ „๋‹ฌํ•˜๊ณ  ์žˆ๋‹ค. 
    //    react-testing-library์—์„œ๋Š” ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•  ์ปดํฌ๋„ŒํŠธ๋ฅผ render()ํ•จ์ˆ˜์˜ ์ธ์ž๋กœ ์ „๋‹ฌํ•œ๋‹ค.
    // 2. ๋‘๋ฒˆ์งธ ์ค„์— ์žˆ๋Š” screen์˜ ๋‹ค์–‘ํ•œ ๋ฉ”์†Œ๋“œ ์ค‘ getByText() ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•˜์—ฌ
    //    render()์—์„œ ๊ฐ€์ ธ์˜จ App ์ปดํฌ๋„ŒํŠธ ์ค‘ "learn react"๋ผ๋Š” ๋ฌธ์ž์—ด์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜์—ฌ linkElement์— ํ• ๋‹นํ•˜๊ณ  ์žˆ๋‹ค. 
    //    (โ€œiโ€๋Š” Regular Expression์œผ๋กœ "i"๋ฅผ ๋ถ™์ž„์œผ๋กœ์จ ๋Œ€์†Œ๋ฌธ์ž๋ฅผ ๊ตฌ๋ถ„ํ•˜์ง€ ์•Š๊ฒŒ ๋งŒ๋“ค์–ด ์ค€๋‹ค.)
    // 3. ์„ธ๋ฒˆ์งธ ์ค„์—์„œ๋Š” expect ํ•จ์ˆ˜์˜ ์ธ์ž๋กœ ์ง€์ •ํ•œ ์š”์†Œ๊ฐ€ document.body์— ์กด์žฌํ•˜๋Š”์ง€ 
    //    toBeInTheDocument ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ฒดํฌํ•˜๊ณ  ์žˆ๋‹ค. 
    //    ์—ฌ๊ธฐ์„œ toBeInTheDocument ํ•จ์ˆ˜๋Š” matchers ํ•จ์ˆ˜๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค.
    //    
    // test, expect -> Jest ํ•จ์ˆ˜
    // toBeInTheDocument -> Jest-dom ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ Costom matchers
    // jset-dom ์€ setupTest.js ์—์„œ import ๋˜๊ณ  ์žˆ๋‹ค.
  • ์ปดํฌ๋„ŒํŠธ ๋žœ๋”(render)ํ•ด์„œ ์ด๋ฒคํŠธ ๊ด€๋ จ ํ…Œ์ŠคํŠธํ•˜๊ธฐ

    • screen : render()์—์„œ ๊ฐ€์ ธ์˜จ ์ปดํฌ๋„ŒํŠธ ์ค‘ ํŠน์ • ์š”์†Œ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.
    • fireEvent : ํ…Œ์ŠคํŠธ ์‹œ ์ด๋ฒคํŠธ ์ž‘๋™ ๊ตฌํ˜„
    • expect(โ€ฆ) .not. toBeDisabled() โ†’ ์ด๋ ‡๊ฒŒ not ์„ ๋ถ™์—ฌ ๋ฐ˜๋Œ€ ์ƒํ™ฉ ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅ
    import { fireEvent, render, screen } from "@testing-library/react"
    import Light from "./Light"
    
    describe("์ปดํฌ๋„ŒํŠธ ํ…Œ์ŠคํŠธ", () => {
        it("render Light Component", () => {
            render(<Light name="์ „์›" />);
            const nameElement = screen.getByText(/์ „์› off/i);
            expect(nameElement).toBeInTheDocument();
        })
    
        test("off button disabled", () => {
            render(<Light name="์ „์›" />);
            const offButtonElement = screen.getByRole("button", {name: "OFF"});
            //getByRole ๋กœ ๋ฒ„ํŠผ๋งŒ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ฒ„ํŠผ์ด 2๊ฐœ์ด๋ฏ€๋กœ, name ์„ ์ด์šฉํ•ด ํŠน์ •ํ•˜๊ธฐ
            expect(offButtonElement).toBeDisabled();
        })
    
        it("on button enable", () => {
            render(<Light name="์ „์›" />);
            const onButtonElement = screen.getByRole("button", {name: "ON"});
            expect(onButtonElement).not.toBeDisabled();
            //not์„ ๋ถ™์ด๋ฉด toBeDisabled ๊ฐ€ ์•„๋‹ ๋•Œ ํ†ต๊ณผ
        })
    
        //ํด๋ฆญ ์ด๋ฒคํŠธ ์œ ๋ฌด๋„ ํ…Œ์ŠคํŠธ๋กœ ๊ตฌํ˜„ => fireEvent ์‚ฌ์šฉ
        //fireEvent ์˜ click ๋ฉ”์„œ๋“œ์— ์ „๋‹ฌ์ธ์ž๋กœ ํ…Œ์ŠคํŠธํ•˜๊ณ ์ž ํ•˜๋Š” ์š”์†Œ ์ „๋‹ฌ
        test("change from off to on", () => {
            render(<Light naem="์ „์›" />);
            const onButtonElement = screen.getByRole('button', {name: "ON"});
            fireEvent.click(onButtonElement);
            expect(onButtonElement).toBeDisabled();
        })
    })

About

๐Ÿงช TDD : ๋ฆฌ์•กํŠธ์—์„œ test ์ž‘์„ฑํ•ด๋ณด๊ธฐ


Languages

Language:JavaScript 67.4%Language:HTML 21.2%Language:CSS 11.5%