ํ”„๋ก ํŠธ์—”๋“œ ํ…Œ์ŠคํŠธ ๋„๊ตฌ ( MSW, Vitest, React Testing Library )

2026. 1. 21. 00:33ยท๐Ÿ’™ ํ”„๋ก ํŠธ์—”๋“œ(FE)
728x90

1. MSW ๋ฐฉ์‹์˜ mocking ์„œ๋ฒ„ ๊ตฌํ˜„

  • feat.md ์— ๋”ฐ๋ผ์„œ ๊ฐœ๋ฐœ์ง„ํ–‰.
  • ๋™์ž‘ ์ฒดํฌ~
    • ์„œ๋ฒ„ ์‹คํ–‰
    • service worker ๊ธฐ๋ฐ˜ ์‘๋‹ต ํ™•์ธ
  • ๊ตฌ์กฐ ์ดํ•ด ๋ฐ MSW ํ•™์Šต

์ฐธ๊ณ . Service Worker

  • Service Worker ๋“ฑ๋ก:
    • ์‹œ์ž‘์ฝ”๋“œ, worker.start() ์‹คํ–‰
    • mockServiceWorker.js ํŒŒ์ผ์„ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์Šค๋ ˆ๋“œ์— ๋“ฑ๋ก
  • ๋„คํŠธ์›Œํฌ ๊ฐ€๋กœ์ฑ„๊ธฐ
    • ๋ชจ๋“  fetch ์š”์ฒญ์„ ๋„คํŠธ์›Œํฌ๋กœ ๋‚˜๊ฐ€๊ธฐ ์ „์— ๊ฐ€๋กœ์ฑ”.
    • ๊ฐ€๋กœ์ฑˆ ์š”์ฒญ(URL, ๋ฉ”์„œ๋“œ)์„ handlers.js์— ์ •์˜๋œ Mock ๋ชฉ๋ก๊ณผ ๋น„๊ตํ•˜์—ฌ ์ผ์น˜ํ•˜๋Š” ํ•ธ๋“ค๋Ÿฌ ์ฐพ๊ธฐ
    • ์ผ์น˜์‹œ : ์‹ค์ œ ์„œ๋ฒ„ ํ†ต์‹  ์—†์ด ํ•ธ๋“ค๋Ÿฌ์— ์ •์˜๋œ Mock ๋ฐ์ดํ„ฐ(JSON)๋ฅผ ์ฆ‰์‹œ ์ƒ์„ฑ
    • ๋ถˆ์ผ์น˜ : ์š”์ฒญ์„ bypassํ•˜์—ฌ ํ†ต๊ณผ
  • Service Worker๋Š” ์ด Mock ์‘๋‹ต์„ ์›น ํŽ˜์ด์ง€์˜ fetch ํ˜ธ์ถœ ์ง€์ ์œผ๋กœ ๋ฐ˜ํ™˜


2. ๋‹จ์œ„ํ…Œ์ŠคํŠธ์™€ ํ†ตํ•ฉํ…Œ์ŠคํŠธ

์†Œํ”„ํŠธ์›จ์–ด ํ…Œ์ŠคํŠธ ๋‹จ๊ณ„

  • ์ถ”๊ฐ€๋กœ E2E ํ…Œ์ŠคํŠธ
    • FE : ๋ธŒ๋ผ์šฐ์ € ๋˜๋Š” headless ๋ธŒ๋ผ์šฐ์ € ๊ธฐ๋ฐ˜ ๋™์ž‘ ํ…Œ์ŠคํŠธ
    • BE: API ์š”์ฒญ๊ณผ ์‘๋‹ต ํ…Œ์ŠคํŠธ

2.1 ํ…Œ์ŠคํŠธ์˜ ๋Œ€์ƒ ์„ ์ •

  • TodoAPP์„ ์–ด๋–ป๊ฒŒ ํ…Œ์ŠคํŠธ ํ• ๊นŒ? ๋ญ˜ ํ…Œ์ŠคํŠธ ํ•ด์•ผํ• ๊นŒ?
  • TodoAPP ? TodoInput? TodoList? Hook?

2.2 ๋‹จ์œ„ ํ…Œ์ŠคํŠธ์™€ ํ†ตํ•ฉํ…Œ์ŠคํŠธ

๋‹จ์œ„ ํ…Œ์ŠคํŠธ (Unit Test)ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ (Integration Test)

์ •์˜ ๊ฐœ๋ณ„ ์ปดํฌ๋„ŒํŠธ/ํ•จ์ˆ˜๋ฅผ ๋…๋ฆฝ์ ์œผ๋กœ ํ…Œ์ŠคํŠธ ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ํ•จ๊ป˜ ๋™์ž‘ํ•˜๋Š”์ง€ ํ…Œ์ŠคํŠธ
๋ฒ”์œ„ ํ•˜๋‚˜์˜ ์ปดํฌ๋„ŒํŠธ/ํ•จ์ˆ˜ ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ + ์˜์กด์„ฑ
์‹คํ–‰ ์†๋„ ๋น ๋ฆ„ (์ˆ˜ ms) ์ƒ๋Œ€์ ์œผ๋กœ ๋А๋ฆผ
๋ชฉ์  ๊ฐœ๋ณ„ ๋กœ์ง์˜ ์ •ํ™•์„ฑ ๊ฒ€์ฆ ํ†ตํ•ฉ๋œ ๋™์ž‘ ๊ฒ€์ฆ(์ „์ฒด ์‹œ์Šคํ…œ ๋ ˆ๋ฒจ๊นŒ์ง€)
๋ชจํ‚น ์™ธ๋ถ€ ์˜์กด์„ฑ ๋ชจํ‚น ์ตœ์†Œํ•œ์˜ ๋ชจํ‚น (์‹ค์ œ ๋™์ž‘ ์œ ์‚ฌ)
์‹คํŒจ ์‹œ ์›์ธ ๋ช…ํ™•ํ•จ (ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ) ํŒŒ์•… ํ•„์š” (์—ฌ๋Ÿฌ ์š”์†Œ ์ค‘ ํ•˜๋‚˜)
์œ ์ง€๋ณด์ˆ˜ ์‰ฌ์›€ ์ƒ๋Œ€์ ์œผ๋กœ ์–ด๋ ค์›€
์‹ ๋ขฐ๋„ ๋ถ€๋ถ„์  ์‹ ๋ขฐ ๋†’์€ ์‹ ๋ขฐ (์‹ค์ œ ์‚ฌ์šฉ ํŒจํ„ด)

2.3 ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ์„ค๊ณ„ ์›์น™

  • ๋…๋ฆฝ์„ฑ
    • ๊ฐ ํ…Œ์ŠคํŠธ๋Š” ๋‹ค๋ฅธ ํ…Œ์ŠคํŠธ์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์•„์•ผํ•จ.
    • mock ์„ ํ™œ์šฉํ•ด์„œ ์™ธ๋ถ€ ์˜์กด์„ฑ ์ œ๊ฑฐ
  • ๋ช…ํ™•์„ฑ
    • ํ…Œ์ŠคํŠธ ์ด๋ฆ„๋งŒ ๋ด๋„ ๋ฌด์—‡์„ ๊ฒ€์ฆํ•˜๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ์–ด์•ผ ํ•จ
    • ํ•˜๋‚˜์˜ ํ…Œ์ŠคํŠธ๋Š” ํ•˜๋‚˜์˜ ๋™์ž‘๋งŒ ๊ฒ€์ฆ
  • ์ˆœ์ˆ˜์„ฑ(๋ฐ˜๋ณต๊ฐ€๋Šฅ์„ฑ)
    • ๊ฐ™์€ ์ž…๋ ฅ์€ ํ•ญ์ƒ ๊ฐ™์€ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜
    • ์™ธ๋ถ€ ํ™˜๊ฒฝ(์‹œ๊ฐ„, ๋žœ๋ค, ๋„คํŠธ์›Œํฌ)์— ์˜์กดํ•˜์ง€ ์•Š์Œ
  • ๋น ๋ฅธ ์‹คํ–‰
    • ๊ฐœ๋ฐœ์ž๊ฐ€ ์‰ฝ๊ฒŒ ์ž์ฃผ ํ…Œ์ŠคํŠธ ํ•  ์ˆ˜ ์žˆ์–ด์•ผํ•จ.

2.4 ๋‹จ์œ„ ์ปดํฌ๋„ŒํŠธ ํ…Œ์ŠคํŠธ ์ „๋žต

ํ•˜๋‚˜์˜ ์ปดํฌ๋„ŒํŠธ -> ํ•˜๋‚˜์˜ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ์™€ ๋น„์Šท

  • ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋Š” ์˜์กด์„ฑ์ด ์—†๋Š” ๋…๋ฆฝ์ ์ธ ๋Œ€์ƒ์ด ์ ์ ˆ
    • TodoInput
    • TodoList
  • TodoInput ์—์„œ๋Š” ์–ด๋–คํ…Œ์ŠคํŠธ๋ฅผ ํ•ด์•ผํ• ๊นŒ?
    • TodoInput ์˜ ์—ญํ• ์€ ๋ฌด์—‡์ธ๊ฐ€?
      • Props ๋ฅผ ๋ฐ›์•„์„œ ๋™์ž‘
      • ์‚ฌ์šฉ์ž ์ธํ„ฐ๋ž™์…˜ ๊ฒ€์ฆ
      • ์ž…๋ ฅ๊ฐ’ ๊ฒ€์ฆ ๋กœ์ง ํ™•์ธ
    • ์—ญํ•  ๊ธฐ๋ฐ˜์œผ๋กœ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ๊ตฌํ˜„์„ ๋ถ€ํƒํ•œ๋‹ค.
    • ์ฝ”๋“œ ์ดํ•ดํ•˜๊ธฐ.
  • TodoList ์˜ ์—ญํ• ์€?
    • Props ๋ณ€๊ฒฝ์— ๋”ฐ๋ฅธ UI ๋ณ€ํ™”
    • ๋ฐ์ดํ„ฐ ๋ Œ๋”๋ง
    • ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง(๋กœ๋”ฉ์ด ์žˆ๋‹ค๋ฉด, ๋นˆ๋ชฉ๋ก์€ ?)
  • useFetch
    • API ํ˜ธ์ถœ ์ž˜ ๋˜๋‚˜?
    • ์ƒํƒœ๊ด€๋ฆฌ ํ™•์ธ
    • fetch API ๋ชจํ‚น ๋˜๋Š” MSW ์—ฐ๋™๋ฐฉ์‹
  • TodoApp ํ…Œ์ŠคํŠธ ํ•ด์•ผํ•˜๋‚˜?
    • ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ
    • ์ „์ฒด ํ”Œ๋กœ์šฐ ๋™์ž‘ ํ™•์ธ
    • ์ปดํฌ๋„ŒํŠธ ๊ฐ„ ์ƒํ˜ธ์ž‘์šฉ ํ™•์ธ

3. Vitest์™€ React Testing Library

Vitest์™€ React Testing Library (RTL)๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ด ํ˜„์žฌ์˜ ์ฃผ๋ฅ˜ ์ค‘ ํ•˜๋‚˜

3.1. Vitest: (Test Runner)

Vitest๋Š” Vite ๊ธฐ๋ฐ˜์˜ ๋น ๋ฅด๊ณ  ํšจ์œจ์ ์ธ ํ…Œ์ŠคํŠธ ๋Ÿฌ๋„ˆ๋กœ, Jest์˜ API๋ฅผ ์™„๋ฒฝํ•˜๊ฒŒ ์ง€์›ํ•œ๋‹ค. Jest์˜ API์™€ ๋™์ผํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜์—ฌ ํ…Œ์ŠคํŠธ ์‹คํ–‰ ํ™˜๊ฒฝ๊ณผ ๊ฒ€์ฆ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค.

(์˜ˆ์ „์—๋Š” Mocha, QUnit, Karma ๋“ฑ์ด ์žˆ์—ˆ์Œ)

๊ธฐ๋Šฅ์—ญํ• ์˜ˆ์‹œ ์ฝ”๋“œ

ํ…Œ์ŠคํŠธ ์ •์˜ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค์™€ ๊ทธ๋ฃน์„ ์ •์˜ํ•œ๋‹ค. test('์„ค๋ช…', () => {})
๊ฒ€์ฆ (expect) ํŠน์ • ๊ฐ’์ด ๊ธฐ๋Œ€ํ•˜๋Š” ๊ฐ’๊ณผ ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธํ•œ๋‹ค. expect(value).toBe(1)
Mocking ํ•จ์ˆ˜๋‚˜ ๋ชจ๋“ˆ์˜ ์‹ค์ œ ๋™์ž‘์„ ๋Œ€์ฒดํ•˜์—ฌ ๊ฒฉ๋ฆฌํ•œ๋‹ค. const mockFn = vi.fn()
๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ๋น„๋™๊ธฐ ์ฝ”๋“œ๊ฐ€ ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฐ๋‹ค. test('...', async () => {})

3.2. React Testing Library (RTL)

RTL์€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋งํ•˜๊ณ  ์‚ฌ์šฉ์ž์ฒ˜๋Ÿผ ์ƒํ˜ธ์ž‘์šฉํ•˜๋ฉฐ DOM์„ ๊ฒ€์ƒ‰ํ•˜๋Š” ์œ ํ‹ธ๋ฆฌํ‹ฐ ์„ธํŠธ๋‹ค.

RTL์˜ ๋ชฉํ‘œ: "์‚ฌ์šฉ์ž๊ฐ€ ์‹ค์ œ๋กœ ๋ณด๋Š” ๋ฐฉ์‹๋Œ€๋กœ ํ…Œ์ŠคํŠธํ•˜๋ผ"

๊ธฐ๋Šฅ์—ญํ• ์˜ˆ์‹œ ์ฝ”๋“œ

๋ Œ๋”๋ง ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์— ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋งํ•œ๋‹ค. render()
DOM ์ฟผ๋ฆฌ ์‚ฌ์šฉ์ž๊ฐ€ ๋ณด๋Š” ๋ฐฉ์‹์œผ๋กœ ์š”์†Œ๋ฅผ ๊ฒ€์ƒ‰ํ•œ๋‹ค. screen.getByRole('button')
์‚ฌ์šฉ์ž ์ด๋ฒคํŠธ ์‹ค์ œ ์‚ฌ์šฉ์ž์˜ ํ‚ค๋ณด๋“œ ์ž…๋ ฅ, ํด๋ฆญ ๋“ฑ์„ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ํ•œ๋‹ค. await userEvent.click(element)

3.3. ์„ค์น˜ ๋ฐ ์„ค์ •

  • vitest, jsdom, c8 ๋“ฑ์˜ ๋ชจ๋“ˆ์„ ์„ค์น˜ํ•˜๊ณ 
  • vite.config.ts ํŒŒ์ผ์— ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ(์˜ˆ: globals: true, environment: 'jsdom')์„ ์„ค์ •

3.4 ํ…Œ์ŠคํŠธ ๊ตฌ์กฐ

์‹ค์ œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ธฐ ์ „์—, Vitest/Jest์™€ ๊ฐ™์€ ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ์š”๊ตฌํ•˜๋Š” ํ…Œ์ŠคํŠธ ํŒŒ์ผ์˜ ๊ธฐ๋ณธ ๊ตฌ์กฐ์™€ ๊ฐ ํ‚ค์›Œ๋“œ์˜ ์—ญํ• ์„ ๋จผ์ € ์ดํ•ดํ•˜๊ธฐ.

1. describe: ํ…Œ์ŠคํŠธ ๊ทธ๋ฃนํ™” (Grouping)

  • ๊ด€๋ จ๋œ ํ…Œ์ŠคํŠธ๋“ค์„ ๋…ผ๋ฆฌ์ ์œผ๋กœ ๋ฌถ์–ด์ฃผ๋Š” ํ•จ์ˆ˜. ์ผ๋ฐ˜์ ์œผ๋กœ ํ…Œ์ŠคํŠธ ๋Œ€์ƒ ์ปดํฌ๋„ŒํŠธ๋‚˜ ๋ชจ๋“ˆ์˜ ์ด๋ฆ„์œผ๋กœ ์‚ฌ์šฉ
describe('TodoInput ์ปดํฌ๋„ŒํŠธ ํ…Œ์ŠคํŠธ', () => {
    // ์—ฌ๊ธฐ์— ๋ชจ๋“  test() ํ•จ์ˆ˜๋“ค์ด ๋“ค์–ด๊ฐ
});

2. test ๋˜๋Š” it: ๊ฐœ๋ณ„ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค (Test Case)

  • ์‹ค์ œ๋กœ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ๊ฒ€์ฆ(Assertion)์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฐ€์žฅ ์ž‘์€ ๋‹จ์œ„
  • ํ•˜๋‚˜์˜ test๋Š” ํ•˜๋‚˜์˜ ๋…๋ฆฝ์ ์ธ ์‹œ๋‚˜๋ฆฌ์˜ค๋งŒ ๊ฒ€์ฆํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Œ
  • ํ…Œ์ŠคํŠธ์˜ ์ด๋ฆ„์€ "๋ฌด์—‡์„ ํ–ˆ์„ ๋•Œ (When), ๋ฌด์—‡์ด ๋˜์–ด์•ผ ํ•œ๋‹ค (Should)"์™€ ๊ฐ™์ด ์„œ์ˆ ์ ์œผ๋กœ ์ž‘์„ฑ
test('์‚ฌ์šฉ์ž๊ฐ€ ํ…์ŠคํŠธ๋ฅผ ์ž…๋ ฅํ•  ์ˆ˜ ์žˆ๋‹ค', async () => {
  // ..๊ถ์‹œ๋  ์–ด์ฉŒ๊ตฌ 
});

// 'it'๋„ 'test'์™€ ์™„์ „ํžˆ ๋™์ผํ•œ ๊ธฐ๋Šฅ.
it('๋ฒ„ํŠผ์„ ํด๋ฆญํ–ˆ์„ ๋•Œ ํŠน์ • ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜์–ด์•ผ ํ•œ๋‹ค', () => {
});

3. Given-when-then ๋ฐฉ์‹์˜ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค ๊ตฌํ˜„

ํšจ์œจ์ ์ด๊ณ  ์ฝ๊ธฐ ์‰ฌ์šด ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ธฐ ์œ„ํ•ด Given-When-Then (GWT) ๊ตฌ์กฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Œ.

์ด ํŒจํ„ด์€ ๋ชจ๋“  ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค์— ๋ช…ํ™•ํ•œ ํ๋ฆ„๊ณผ ๋ชฉ์ ์„ ๋ถ€์—ฌํ•จ

  • Given
    • ์ค€๋น„๋‹จ๊ณ„, ํ…Œ์ŠคํŠธ์— ํ•„์š”ํ•œ ์ดˆ๊ธฐ ์กฐ๊ฑด(๋ Œ๋”๋ง, Mock ํ•จ์ˆ˜)์„ ์„ค์ •
  • When
    • ์‹คํ–‰ ๋‹จ๊ณ„, ํ…Œ์ŠคํŠธํ•˜๋ ค๋Š” ํŠน์ • ํ–‰๋™(์‚ฌ์šฉ์ž ์ƒํ˜ธ์ž‘์šฉ)์„ ์‹คํ–‰
  • Then
    • assertion, ์‹คํ–‰ ๊ฒฐ๊ณผ๊ฐ€ ์˜ˆ์ƒ๋Œ€๋กœ ๋‚˜ํƒ€๋‚ฌ๋Š”์ง€ expect๋กœ ํ™•์ธ
test('๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜์–ด์•ผ ํ•œ๋‹ค', async () => {
  // Given
  const mockOnAdd = vi.fn();
  render(<TodoInput onAddTodo={mockOnAdd} isLoading={false} />);
  
  // When
  await userEvent.click(screen.getByText('์ถ”๊ฐ€'));
  
  // Then
  expect(mockOnAdd).toHaveBeenCalled();
});

3. Setup/Teardown: ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ ์ค€๋น„์™€ ์ •๋ฆฌ

  • ํ…Œ์ŠคํŠธ๊ฐ€ ์‹คํ–‰๋˜๊ธฐ ์ „ํ›„์— ๋ฐ˜๋ณต์ ์œผ๋กœ ํ•„์š”ํ•œ ์ค€๋น„ ์ž‘์—…(Setup)๊ณผ ์ •๋ฆฌ ์ž‘์—…(Teardown)์„ ์ฒ˜๋ฆฌ
  • ์ด๋Š” ํ…Œ์ŠคํŠธ ๊ฐ„์˜ ๋…๋ฆฝ์„ฑ(Isolation)์„ ์œ ์ง€ํ•˜๋Š” ๋ฐ ๋งค์šฐ ์ค‘์š”

ํ‚ค์›Œ๋“œ์‹คํ–‰ ์‹œ์ ์—ญํ• 

beforeEach ๊ฐ test ํ•จ์ˆ˜ ์‹คํ–‰ ์ง์ „ ๊ฐ ํ…Œ์ŠคํŠธ๊ฐ€ ๋…๋ฆฝ์ ์œผ๋กœ ์‹คํ–‰๋˜๋„๋ก ์ดˆ๊ธฐ ์ƒํƒœ๋ฅผ ์„ค์ •ํ•˜๊ฑฐ๋‚˜ Mocking์„ ์žฌ์„ค์ •. (๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉ๋จ)
afterEach ๊ฐ test ํ•จ์ˆ˜ ์‹คํ–‰ ์งํ›„ ๊ฐ ํ…Œ์ŠคํŠธ๊ฐ€ ๋๋‚œ ํ›„ DOM์„ ์ •๋ฆฌ(cleanup)ํ•˜๊ฑฐ๋‚˜ Mocking ์ƒํƒœ๋ฅผ ์ดˆ๊ธฐํ™”.
beforeAll describe ๊ทธ๋ฃน ์ „์ฒด ์‹œ์ž‘ ์ „ ๋ชจ๋“  ํ…Œ์ŠคํŠธ์— ๊ฑธ์ณ ํ•œ ๋ฒˆ๋งŒ ํ•„์š”ํ•œ ์ „์—ญ ์„ค์ •(์˜ˆ: MSW worker ์‹œ์ž‘)์„ ์ฒ˜๋ฆฌ.
afterAll describe ๊ทธ๋ฃน ์ „์ฒด ์ข…๋ฃŒ ํ›„ ๋ชจ๋“  ํ…Œ์ŠคํŠธ๊ฐ€ ๋๋‚œ ํ›„ ์ „์—ญ ์ž์›(์˜ˆ: MSW worker ์ข…๋ฃŒ)์„ ํ•ด์ œ

4. ๊ตฌํ˜„ํ•˜๊ธฐ ์ „ ์ฃผ์š” ๊ฐœ๋…๋“ค

4.1. ์š”์†Œ ๊ฒ€์ƒ‰ (DOM Query)

  • ์‚ฌ์šฉ์ž๊ฐ€ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ์†์„ฑ (Role, Text, Label ๋“ฑ)์„ ๊ธฐ์ค€์œผ๋กœ DOM ์š”์†Œ๋ฅผ ์ฐพ๋Š”๋‹ค.
  • getBy๋Š” ์š”์†Œ๋ฅผ ์ฐพ์ง€ ๋ชปํ•˜๋ฉด ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๊ณ , queryBy๋Š” null์„ ๋ฐ˜ํ™˜
screen.getByRole('button');

4.2. ๊ฐ’ ๊ฒ€์ฆ (Assertion)

  • ํŠน์ • ๊ฐ’์ด๋‚˜ ์š”์†Œ์˜ ์ƒํƒœ๊ฐ€ ๊ธฐ๋Œ€ํ•˜๋Š” ๊ฒฐ๊ณผ์™€ ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธ
  • RTL์˜ ์ปค์Šคํ…€ Matchers (toBeInTheDocument ๋“ฑ)์™€ Vitest/Jest์˜ ๊ธฐ๋ณธ Matchers (toHaveValue, toBe ๋“ฑ)๋ฅผ ํ•จ๊ป˜ ์‚ฌ์šฉ
expect(input).toHaveValue('๊ฐ’');

4.3. ํ•จ์ˆ˜ ํ˜ธ์ถœ ๊ฒ€์ฆ

  • Mock ํ•จ์ˆ˜ (vi.fn())๊ฐ€ ์˜๋„๋Œ€๋กœ ํ˜ธ์ถœ๋˜์—ˆ๋Š”์ง€, ๊ทธ๋ฆฌ๊ณ  ํ˜ธ์ถœ ์‹œ ์˜ฌ๋ฐ”๋ฅธ ์ธ์ž๋ฅผ ์ „๋‹ฌ๋ฐ›์•˜๋Š”์ง€ ํ™•์ธ
expect(mockFn).toHaveBeenCalledWith('hello');

4.4. ํด๋ฆญ ์ด๋ฒคํŠธ (Interaction)

  • ๋ฒ„ํŠผ ํด๋ฆญ, ์ฒดํฌ๋ฐ•์Šค ํ† ๊ธ€ ๋“ฑ ๋งˆ์šฐ์Šค ์ƒํ˜ธ์ž‘์šฉ์„ ์‹ค์ œ ์‚ฌ์šฉ์ž์ฒ˜๋Ÿผ ์‹œ๋ฎฌ๋ ˆ์ด์…˜
  • userEvent๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด fireEvent๋ณด๋‹ค ์‹ค์ œ ๋ธŒ๋ผ์šฐ์ €์™€ ์œ ์‚ฌํ•˜๊ฒŒ ๋™์ž‘ํ•˜๋ฏ€๋กœ ๊ถŒ์žฅ
await userEvent.click(button);

4.5. ํ‚ค๋ณด๋“œ ์ž…๋ ฅ (Interaction)

  • ํ…์ŠคํŠธ ์ž…๋ ฅ, ์—”ํ„ฐ ํ‚ค, ํƒญ ์ด๋™ ๋“ฑ ํ‚ค๋ณด๋“œ ์ƒํ˜ธ์ž‘์šฉ์„ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ํ•˜๋ฉฐ, onChange ์ด๋ฒคํŠธ์™€ ์ž…๋ ฅ ์ƒํƒœ๋ฅผ ์ •ํ™•ํ•˜๊ฒŒ ๋ฐ˜์˜
await userEvent.type(input, 'ํ…์ŠคํŠธ');

4.6. ๋น„๋™๊ธฐ ๋Œ€๊ธฐ (Asynchronous)

  • API ์‘๋‹ต, UI ์—…๋ฐ์ดํŠธ, ์ƒํƒœ ๋ณ€๊ฒฝ ๋“ฑ ๋น„๋™๊ธฐ ์ž‘์—…์ด ์™„๋ฃŒ๋˜์–ด ํŠน์ • ์กฐ๊ฑด์ด ์ถฉ์กฑ๋  ๋•Œ๊นŒ์ง€ ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์„ ๋Œ€๊ธฐ
await waitFor(() => {
  expect(screen.getByText('๊ฒฐ๊ณผ')).toBeInTheDocument();
});

5. ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ ํ…Œ์ŠคํŠธ ๊ตฌํ˜„ํ•˜๊ธฐ

  • Input ์ปดํฌ๋„ŒํŠธ
  • ๋ฆฌ์ŠคํŠธ ์ปดํฌ๋„ŒํŠธ
  • ์ปค์Šคํ…€ ํ›…
    • ๋ฆฌ์ŠคํŠธ๊ฐ€์ ธ์˜ค๊ธฐ, ์ถ”๊ฐ€ํ•˜๊ธฐ, 500์—๋Ÿฌ ๋Œ€์‘ํ•˜๊ธฐ
    • ๋ชจํ‚น vs. MSW
      • MSW๋ฅผ ์“ฐ๋ฉด fetch ๋ชจํ‚น์„ ์ œ๊ฑฐํ•˜๊ณ  ์‹ค์ œ fetch๋ฅผ ๊ทธ๋Œ€๋กœ ํ…Œ์ŠคํŠธํ•˜๋‹ˆ๊นŒ ๋” ๊น”๋”ํ•˜๊ณ  ์‹ ๋ขฐ๋„๋„ ๋†’์€ํŽธ.

6. E2E ํ…Œ์ŠคํŠธ(End to End)

  • ์‹ค์ œ ์‚ฌ์šฉ์ž๊ฐ€ ์„œ๋น„์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ธŒ๋ผ์šฐ์ € ํ™˜๊ฒฝ ์ „์ฒด๋ฅผ ์ž๋™ํ™”ํ•˜์—ฌ ํ…Œ์ŠคํŠธํ•˜๋Š” ๋ฐฉ์‹
  • ๊ฐ€์žฅ๋†’์€ ์‹ ๋ขฐ๋„
    • UI + Networking + Routing + DOM ๋ Œ๋”๋ง
  • ์‹ค์ œ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์‹คํ–‰(chromium, webkit, firefox)
  • ๋‹จ์œ„๋ณด๋‹ค ๋А๋ฆฌ์ง€๋งŒ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ๊ฒ€์ฆํ•  ์ˆ˜ ์žˆ์Œ

FE ๋„๊ตฌ๋“ค

  • Cypress, Playwright

Playwright ํŠน์ง•๋“ค

  • DOM์ด ๋‚˜ํƒ€๋‚ ๋•Œ๊นŒ์ง€ ์ž๋™์œผ๋กœ ๊ธฐ๋‹ค๋ฆฐ๋‹ค
  • waitFor๋“ฑ ๋ถˆํ•„์š”. ๋„คํŠธ์›Œํฌ ์š”์ฒญ, ๋ Œ๋”๋ง ์ž๋™๊ฐ์ง€
  • DOM์š”์†Œ๋ฅผ ์‰ฝ๊ฒŒ ์ฐพ๋Š”ํŽธ.
  • ์Šค๋ƒ…์ƒต, ๋…นํ™”(recorder)๊ธฐ๋Šฅ ์ œ๊ณต.
  • Codegen ์œผ๋กœ ์ž๋™ ํ…Œ์ŠคํŠธ์ฝ”๋“œ ์ƒ์„ฑ.
  • ํ…Œ์ŠคํŠธ๊ฐ€ ๋๋‚˜๋ฉด ์ž๋™์œผ๋กœ HTML ๋ฆฌํฌํŠธ๋ฅผ ์ƒ์„ฑ
    • npx playwright show-report

playWright ์‹คํ–‰์ˆœ์„œ

  1. Playwright test runner ์‹คํ–‰
  2. ๋ธŒ๋ผ์šฐ์ € ์ž๋™ ์‹คํ–‰
  3. ํ…Œ์ŠคํŠธ URL ์ ‘์†
  4. ์‚ฌ์šฉ์ž์˜ ์‹ค์ œ ๋™์ž‘์„ ์‹œ๋ฎฌ๋ ˆ์ด์…˜
  5. DOM ์ƒํƒœ ํ™•์ธ
  6. ํ…Œ์ŠคํŠธ ์ข…๋ฃŒ ๋ฐ ๋ธŒ๋ผ์šฐ์ € ๋‹ซ๊ธฐ
  7. ๊ฒฐ๊ณผ ๋ฆฌํฌํŠธ ์ถœ๋ ฅ (HTML ๋ฆฌํฌํŠธ ํฌํ•จ)

์‚ฌ์šฉ์˜ˆ์‹œ

๋ธŒ๋ผ์šฐ์ € ์—ด๊ธฐ

const browser = await chromium.launch();

์ƒˆ๋กœ์šด ํŽ˜์ด์ง€(page)๋ฅผ ์—ฐ๋‹ค

const page = await browser.newPage();

ํŠน์ • URL๋กœ ์ด๋™

await page.goto('http://localhost:5173/');

ํ–‰๋™์„ ์‹œ๋ฎฌ๋ ˆ์ด์…˜

await page.fill('#todo-input', '์žฅ๋ณด๊ธฐ');
await page.click('button:has-text("์ถ”๊ฐ€")');

์‹ค์ œ DOM ์ƒํƒœ๋ฅผ ํ™•์ธ

await expect(page.locator('li')).toContainText('์žฅ๋ณด๊ธฐ');

์™„๋ฃŒ ํ›„ ๋ธŒ๋ผ์šฐ์ € ์ข…๋ฃŒ

await browser.close();

7. TDD

Test driven development

8. Code Coverage

  • ํ…Œ์ŠคํŠธ๊ฐ€ ์ฝ”๋“œ์˜ ๋ช‡ %๋ฅผ ์‹คํ–‰ํ–ˆ๋Š”์ง€ ๋ณด์—ฌ์ฃผ๋Š” ์ˆ˜์น˜
    • ์˜ˆ) ์ฝ”๋“œ ์ปค๋ฒ„๋ฆฌ์ง€ 80% → ์ „์ฒด ์ฝ”๋“œ ์ค‘ 80%๊ฐ€ ํ…Œ์ŠคํŠธ ์‹คํ–‰ ์ค‘ ์‹ค์ œ๋กœ ์ˆ˜ํ–‰๋จ
  • ํ…Œ์ŠคํŠธ๊ฐ€ ์ถฉ๋ถ„ํžˆ ์ž‘์„ฑ๋˜์—ˆ๋Š”์ง€ ํ™•์ธ
  • CI/CD์—์„œ ํ’ˆ์งˆ ๊ธฐ์ค€์œผ๋กœ ์‚ผ๊ธฐ ์ข‹์Œ

์ปค๋ฒ„๋ฆฌ์ง€์˜ ์ฃผ์š” ์œ ํ˜•

  • ๋ผ์ธ ์ปค๋ฒ„๋ฆฌ์ง€(Line Coverage): ๋ช‡ ์ค„์ด ์‹คํ–‰๋๋Š”๊ฐ€
  • ๋ธŒ๋žœ์น˜ ์ปค๋ฒ„๋ฆฌ์ง€(Branch Coverage): if/else ๋“ฑ ๋ถ„๊ธฐ๋ฌธ์ด ๊ฐ ์กฐ๊ฑด๋งˆ๋‹ค ์‹คํ–‰๋๋Š”๊ฐ€
  • ํ•จ์ˆ˜ ์ปค๋ฒ„๋ฆฌ์ง€(Function Coverage): ํ•จ์ˆ˜๋“ค์ด ํ˜ธ์ถœ๋๋Š”๊ฐ€
  • ์Šคํ…Œ์ดํŠธ๋จผํŠธ ์ปค๋ฒ„๋ฆฌ์ง€(Statement Coverage): ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ ๊ตฌ๋ฌธ(statement)์ด ์‹คํ–‰๋๋Š”๊ฐ€

์ฃผ์˜์ 

  • ์ปค๋ฒ„๋ฆฌ์ง€๊ฐ€ ๋†’๋‹ค๊ณ  ํ…Œ์ŠคํŠธ ํ’ˆ์งˆ์ด ๋†’์€ ๊ฑด ์•„๋‹˜
  • ์ค‘์š”ํ•œ ๋กœ์ง๋งŒ ์ž˜ ํ…Œ์ŠคํŠธํ–ˆ๋‹ค๋ฉด ์ปค๋ฒ„๋ฆฌ์ง€๊ฐ€ ๋‚ฎ์•„๋„ ๊ดœ์ฐฎ์„ ์ˆ˜ ์žˆ์Œ

'๐Ÿ’™ ํ”„๋ก ํŠธ์—”๋“œ(FE)' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

ํ”„๋ก ํŠธ์—”๋“œ ์ž์ž˜ํ•œ ํ”ผ๋“œ๋ฐฑ  (0) 2026.01.25
Next.js ์‹œ์ž‘ํ•˜๊ธฐ  (1) 2026.01.22
FE ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ(FE ์•„ํ‚คํ…์ณ)  (0) 2026.01.20
React ์ƒํƒœ๊ด€๋ฆฌ ( ์ง€์—ญ, ์ „์—ญ, ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ )  (0) 2026.01.20
React ์„ฑ๋Šฅ ์ตœ์ ํ™”  (0) 2026.01.20
'๐Ÿ’™ ํ”„๋ก ํŠธ์—”๋“œ(FE)' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€
  • ํ”„๋ก ํŠธ์—”๋“œ ์ž์ž˜ํ•œ ํ”ผ๋“œ๋ฐฑ
  • Next.js ์‹œ์ž‘ํ•˜๊ธฐ
  • FE ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ(FE ์•„ํ‚คํ…์ณ)
  • React ์ƒํƒœ๊ด€๋ฆฌ ( ์ง€์—ญ, ์ „์—ญ, ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ )
์—ฐ์žŽ(lotus leaf)
์—ฐ์žŽ(lotus leaf)
  • ์—ฐ์žŽ(lotus leaf)
    lotus' s develog ๐Ÿƒ
    ์—ฐ์žŽ(lotus leaf)
  • ์ „์ฒด
    ์˜ค๋Š˜
    ์–ด์ œ
    • ๋ถ„๋ฅ˜ ์ „์ฒด๋ณด๊ธฐ (79)
      • โœ๏ธ ๊ฐœ๋ฐœํšŒ๊ณ ๋ก (5)
      • ๐Ÿงฎ ์•Œ๊ณ ๋ฆฌ์ฆ˜ (3)
      • ๐Ÿ’™ ํ”„๋ก ํŠธ์—”๋“œ(FE) (19)
        • HTML (0)
        • CSS (0)
        • Javascript (0)
        • React (0)
        • Next.js (0)
        • webpack & babel (0)
      • ๐Ÿ’ป ๋ฐฑ์—”๋“œ(BE) (2)
        • Nest.js (0)
        • Express.js (0)
        • MySQL (1)
      • โš™๏ธ ์ธํ”„๋ผ(Devops) (2)
      • ๐Ÿค– AI (1)
      • ๐ŸŒ WEB (8)
      • ๐Ÿ’ป CS (16)
        • ์ž๋ฃŒ๊ตฌ์กฐ (0)
        • ์ปดํ“จํ„ฐ ๋„คํŠธ์›Œํฌ (1)
        • ์šด์˜์ฒด์ œ (0)
        • ์ธ๊ณต์ง€๋Šฅ (8)
        • ์›น ๋ณด์•ˆ (1)
        • ํด๋ผ์šฐ๋“œ ์ปดํ“จํŒ… (6)
      • ๐Ÿ–‹๏ธ DevLog (1)
      • ๐Ÿฆพ ๋กœ๋ณดํ‹ฑ์Šค (4)
      • ๐Ÿ“— ๋„ค์ด๋ฒ„๋ถ€์ŠคํŠธ์บ ํ”„ ์›น ๋ชจ๋ฐ”์ผ (0)
      • ๐ŸŽฎ Unity(C#) (10)
      • ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด (4)
        • C (4)
        • C++ (0)
        • Java (0)
        • Python (0)
      • MSA (1)
  • ๋ธ”๋กœ๊ทธ ๋ฉ”๋‰ด

    • ํ™ˆ
    • ํƒœ๊ทธ
    • ๋ฐฉ๋ช…๋ก
  • ๋งํฌ

  • ๊ณต์ง€์‚ฌํ•ญ

  • ์ธ๊ธฐ ๊ธ€

  • ํƒœ๊ทธ

    isaac automator
    ์•Œ๊ณ ๋ฆฌ์ฆ˜
    ์ดํ™”์—ฌ์ž๋Œ€ํ•™๊ต #๋„์ „ํ•™๊ธฐ์ œ
    ros bridge
    nav2
    ๋ฆฌ์•กํŠธ
    ํŒŒ์ผํŠธ๋ฆฌ
    ์ŠคํŒธ๋ถ„๋ฅ˜๊ธฐ
    AWS
    advaned detail
    deploy-aws
    c์–ธ์–ด
    ์กฐํ•ฉ
    client-streaming
    auto-scaling
    ๋ฐฑ์ค€
    gaussian rbf svm
    turtlebot
    c++
    ์ˆœ์—ด
    ์ŠคํŒธ๋ฉ”์ผ๋ถ„๋ฅ˜๊ธฐ
    ros workspace
    hard margin svm
    C
    Devops #๋Œ€๊ทœ๋ชจํŠธ๋ž˜ํ”ฝ์ฒ˜๋ฆฌ
    C#
    soft margin svm
    ๊ธฐ์ดˆ์•Œ๊ณ ๋ฆฌ์ฆ˜
    next.js12
    ์ฝ”๋”ํŒจ๋“œ
  • ์ตœ๊ทผ ๋Œ“๊ธ€

  • ์ตœ๊ทผ ๊ธ€

  • hELLOยท Designed By์ •์ƒ์šฐ.v4.10.6
์—ฐ์žŽ(lotus leaf)
ํ”„๋ก ํŠธ์—”๋“œ ํ…Œ์ŠคํŠธ ๋„๊ตฌ ( MSW, Vitest, React Testing Library )
์ƒ๋‹จ์œผ๋กœ

ํ‹ฐ์Šคํ† ๋ฆฌํˆด๋ฐ”