์ฝ๋๋ฅผ ์์ฑํ๊ธฐ ์ ์ ํ ์คํธ๋ฅผ ์ฐ๋ ์ํํธ์จ์ด ๊ฐ๋ฐ ๋ฐฉ๋ฒ๋ก
-
์์ ๋จ์์ ํ ์คํธ ์ผ์ด์ค๋ฅผ ์์ฑํ๊ณ , ์ด๋ฅผ ํต๊ณผํ๋ ์ฝ๋๋ฅผ ์์ฑํ๋ ๊ณผ์ ์ ๋ฐ๋ณตํ๋ ๊ฒ
-
์ด 3๋จ๊ณ๋ก ์ด๋ฃจ์ด์ง๋ค.
โป 1์ ๊ณผ์ ์ ๋ง์น๊ธฐ ์ ๊น์ง 2 ์์ ์ ์์ํ๋ฉด ์๋๋ค!
- Write Failing Test: ์คํจํ๋ ํ ์คํธ ์ฝ๋๋ฅผ ๋จผ์ ์์ฑํ๋ค.
- Make Test Pass: ํ ์คํธ ์ฝ๋๋ฅผ ์ฑ๊ณต์ํค๊ธฐ ์ํ ์ค์ ์ฝ๋๋ฅผ ์์ฑํ๋ค. (ํ ์คํธ๋ฅผ ํต๊ณผํ ์ ๋์ ์ต์ ์ฝ๋๋ง ์์ฑ)
- Refactor: ์ค๋ณต ์ฝ๋ ์ ๊ฑฐ, ์ผ๋ฐํ ๋ฑ์ ๋ฆฌํฉํ ๋ง์ ์ํํ๋ค.
-
TDD๋ฅผ ์ฌ์ฉํ๋ ์ด์
โ ์์์น ๋ชปํ๋ ๋ฒ๊ทธ๋ฅผ ์ค์ฌ ์์ ์๊ฐ์ ์ค์ผ ์ ์๋ค! ์ฒ์์ ์๋๊ฐ ๋๋ฆฌ๋ค๊ณ ๋๋ ์ ์์ผ๋ ์ฅ๊ธฐ์ ์ผ๋ก ๋ณด๋ฉด ์ฒ์๋ถํฐ ๋ฒ๊ทธ๋ฅผ ์ค์ฌ๊ฐ๋ฉฐ ๊ฐ๋ฐํ๋ ๊ฒ์ด ํจ์จ์ ์ด๋ค.
-
Testing Library, Jest ๋๋ค React์์๋ง ์ธ ์ ์๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์๋๋ค.
-
Testing Libarary์ Jest๋ ์ญํ ์ด ๊ฐ๊ฐ ๋ค๋ฅด๊ธฐ ๋๋ฌธ์ React์ ๋ํ ํ ์คํธ๋ฅผ ์งํํ ๋๋ ์ด๋ ํ์ชฝ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ด์ฉํ๋ ๊ฒ๋ง์ผ๋ก๋ ํ ์คํธ๋ฅผ ํ ์ ์๋ค.
โ ๋ ๋ค ์ฌ์ฉ!
- Testing Library๋ ํ ์คํธ๋ฅผ ์คํํ๊ณ ์ถ์ ์ปดํฌ๋ํธ๋ ํด๋ฆญ ์ด๋ฒคํธ๋ฑ ๋ค์ํ ๊ณณ์ ์ธ ์ ์๋ค.
- Testing Libarary์์ React์ฉ React Testing Library์ ์ ๊ณตํ๊ณ ์๊ธฐ ๋๋ฌธ์, create-react-app์ ์ด์ฉํ์ฌ React ํ๋ก์ ํธ๋ฅผ ์์ฑํ๋ฉด ์๋์ผ๋ก Testing Libarary๋ฅผ ์ด์ฉํ ์ ์๋ค.
-
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(); }) })
- screen :