4. Testing Library

1. Jest

Jest ๊ณต์‹๋ฌธ์„œ Jest๋Š” ๋‹จ์ˆœ์„ฑ์— ์ดˆ์ ์„ ๋‘” JavaScript ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ

Jest๋Š” Mocha์™€ Chai์ฒ˜๋Ÿผ RSpec์˜ describe-it์„ ์ง€์›ํ•˜๊ณ , expect๋กœ ๋‹จ์–ธ(assertion) ๊ฐ€๋Šฅ Mocking๋„ ๋‹ค์–‘ํ•œ ๋ ˆ๋ฒจ์—์„œ ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ โ‡’ ๊ฑฐ์˜ ๋ชจ๋“  ๊ฒƒ์„ ๊ฐ–์ถ˜ ํ…Œ์ŠคํŒ… ๋„๊ตฌ ๐Ÿ› 

(์ฐธ๊ณ ) ๋‹ค์–‘ํ•œ ํ…Œ์ŠคํŠธ ๋„๊ตฌ

Mocha

Mocha Node.js ์™€ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์‹คํ–‰๋˜๋Š” ๊ธฐ๋Šฅ์ด ํ’๋ถ€ํ•œ JavaScript ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ

Chai

Mocha๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์“ฐ๋Š” ์–ด์„ค์…˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ expect(), assert(), should-style assertions

RSpec

RSpec Ruby์šฉ ํ…Œ์ŠคํŠธ ๋„๊ตฌ TDD๋ฅผ ์ƒ์‚ฐ์ ์ด๊ณ  ์žฌ๋ฏธ์žˆ๊ฒŒ ๋งŒ๋“ค๊ธฐ๊ฐ€ ์†Œ๊ฐœ ๋ฌธ๊ตฌ ์›์กฐ

  • BETTER SPECS

    • RSpec ๋ฒ ์ŠคํŠธ ํ”„๋ž™ํ‹ฐ์Šค ๋ชจ์Œ

    • ์ด๋Œ€๋กœ ์‚ฌ์šฉํ•  ์ˆ˜๋Š” ์—†์ง€๋งŒ ์ฐธ๊ณ ์šฉ, ํ๋ฆ„์„ ์•Œ ์ˆ˜ ์žˆ์Œ

    • Jest๋Š” RSpec์˜ let ๋“ฑ์„ ์ง€์›ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์—, ํ•ต์‹ฌ ์•„์ด๋””์–ด๋งŒ ์ฐธ๊ณ 

2. ํ…Œ์ŠคํŠธ

๐Ÿž ๋ฒ„๊ทธ๋ฅผ ์ฐพ๋Š” ํ–‰์œ„๋กœ ์ƒ๊ฐํ•˜๊ธฐ ์‰ฌ์›€ ๋ฒ„๊ทธ๋Š” ๊ธฐ๋Œ€ํ•˜์ง€ ์•Š์€(unexpected) ์ผ์ด ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ โ†’ ์ŠคํŽ™, ์‚ฌ์–‘(specification)์„ ๋ช…ํ™•ํžˆ ํ•˜๋Š” ๊ฒƒ์ด ๋งค์šฐ ์ค‘์š” ๐Ÿ’ก ์ŠคํŽ™์— ๋งž๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€๋ฅผ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ด ํ…Œ์ŠคํŠธ

๊ธฐ๋ณธ์ ์ธ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ

test('add', () => {
  expect(add(1, 2)).toBe(3);
});

์ตœ์ดˆ์˜ ๋ฒ„๊ทธ

์ตœ์ดˆ์˜ ๋ฒ„๊ทธ ๊ทธ๋ ˆ์ด์Šค ํ˜ธํผ (Grace Hopper)

์ตœ์ดˆ ์—ฌ์„ฑ ํ”„๋กœ๊ทธ๋ž˜๋จธ ์ค‘ ํ•œ ๋ช… ์ตœ์ดˆ์˜ ๋ฒ„๊ทธ ๋ฐœ๊ฒฌ - ์ง„๊ณต๊ด€์˜ ๋‚˜๋ฐฉ ์ปดํŒŒ์ผ๋Ÿฌ ๊ฐœ๋…์„ ๋งŒ๋“ฆ ์ดˆ๊ธฐ ๊ณ ๊ธ‰ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์ธ COBOL์„ ๊ฐœ๋ฐœ

TDD

ํ…Œ์ŠคํŠธ ์ฃผ๋„ ๊ฐœ๋ฐœ, Test-Driven Development ํ…Œ์ŠคํŠธ๋ฅผ ๋จผ์ € ์ž‘์„ฑํ•˜๊ณ  ๊ทธ ํ›„ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑ

TDD์˜ ์ˆœ์„œ

๐Ÿ”ด Red(Fail) โ†’ ๐ŸŸข Green(Psss) โ†’ ๐Ÿ›  Refactor

  1. ์‹คํŒจํ•˜๋Š” ํ…Œ์ŠคํŠธ ์ž‘์„ฑ

  2. ๋นจ๋ฆฌ ํ†ต๊ณผํ•˜๋„๋ก ์ž‘์„ฑ

  3. ๋ฆฌํŒฉํ† ๋ง์œผ๋กœ ์ฝ”๋“œ ๊ฐœ์„ 

BDD

ํ–‰์œ„ ์ฃผ๋„ ๊ฐœ๋ฐœ, Behavior-Driven Development TDD์˜ ํ•œ ๊ฐˆ๋ž˜

๊ธฐ๋Šฅ(feature) ๋ชฉ๋ก์„ ๋งŒ๋“ค๊ณ  ๊ตฌํ˜„ํ•˜๋ฉด ๋จ(ํ–‰์œ„๋ฅผ ๋จผ์ € ์ž‘์„ฑ) ์ฆ‰, ์†Œํ”„ํŠธ์›จ์–ด์˜ ๋™์ž‘(Behavior)์— ๋Œ€ํ•œ ๊ฒƒ

Give/When/Then ํŒจํ„ด

๋ชจ๋“  BDD ์‹œ๋‚˜๋ฆฌ์˜ค์— ์žˆ๋Š” 3๊ฐ€์ง€ ํ•ต์‹ฌ ์š”์†Œ

  • GIVEN (context, ๋ฌธ๋งฅ ์„ค๋ช…)

  • WHEN (action, ๋™์ž‘ ์„ค๋ช…)

  • THEN (outcome, ๊ฒฐ๊ณผ ์„ค๋ช…)

BDD ์Šคํƒ€์ผ์˜ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ

describe('add', () => {
  it('returns sum of two numbers', () => {
    expect(add(1, 2)).toBe(3);
  });
});

์ผ€์ด์Šค๋ฅผ ๋‚˜๋ˆ  ์ฝ”๋“œ๋ฅผ ์งœ๊ธฐ ๋•Œ๋ฌธ์— ํ‘œํ˜„๋ ฅ์ด ์ข‹์•„์ง€๊ณ , ๋‹ค์–‘ํ•œ ์ƒํ™ฉ์— ๋Œ€ํ•ด ๊ณ ๋ฏผํ•  ์ˆ˜ ์žˆ์Œ

(์ฐธ๊ณ ) Writing BDD Test Scenarios (์ฐธ๊ณ ) Describe-Context-It

2. Describe-Context-It ํŒจํ„ด

์ƒํ™ฉ๋งˆ๋‹ค ๋‹ค๋ฅธ ๋งฅ๋ฝ์„ ๋ฌ˜์‚ฌํ•˜๋Š” ๊ฒƒ ์ฝ”๋“œ์˜ ํ–‰๋™์„ ์„ค๋ช…ํ•˜๋Š” ํŒจํ„ด์ด๊ธฐ ๋•Œ๋ฌธ์— ์ดํ•ดํ•˜๊ธฐ ์‰ฌ์›€

์žฅ์ 

  1. ์“ฐ๊ธฐ ํŽธํ•˜๊ณ  ์ฝ”๋“œ์˜ ์˜๋„๊ฐ€ ๋ช…ํ™•ํ•ด์ง

  2. ๋‹ค์–‘ํ•œ ์ƒํ™ฉ์„ ๊ณ ๋ คํ•  ์ˆ˜ ์žˆ์Œ โ†’ ํ…Œ์ŠคํŠธ ์ปค๋ฒ„๋ฆฌ์ง€์˜ ์ฆ๋Œ€

  3. ์ „์—ญ๋ณ€์ˆ˜๋ฅผ ๋‚จ๋ฐœํ•˜๋Š” ๋ฌธ์ œ ํ•ด๊ฒฐ

์ž‘์„ฑ ๋ฐฉ๋ฒ•

  1. Describe์— ์„ค๋ช…ํ•  ํ…Œ์ŠคํŠธ ๋Œ€์ƒ์„ ๋ช…์‹œ

describe('login', () => {

describe('add ํ•จ์ˆ˜๋Š”', () => {
  1. Context์— ํ…Œ์ŠคํŠธ ๋Œ€์ƒ์ด ๋†“์ธ ์ƒํ™ฉ์„ ๋ช…์‹œ (with ๋˜๋Š” when์œผ๋กœ ์‹œ์ž‘)

context('with correct accountNumber and password', () => {

context('๋‘ ๊ฐœ์˜ ์–‘์ˆ˜๊ฐ€ ์ฃผ์–ด์กŒ์„ ๋•Œ', () => {
  1. It์— ํ…Œ์ŠคํŠธ ๋Œ€์ƒ์˜ ํ–‰๋™์„ ๊ฐ„๋‹จํ•˜๊ฒŒ ์„ค๋ช…

it('load accountNumber information', async () => {

it('๋‘ ์ˆซ์ž์˜ ํ•ฉ์„ ๋Œ๋ ค์ค€๋‹ค', async () => {

3. React Testing Library

React Testing Library ๊ณต์‹๋ฌธ์„œ UI ํ…Œ์ŠคํŠธ์— ํŠนํ™”๋œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

jest-dom jest-dom on GitHub ์ถ”๊ฐ€์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋งค์ฒ˜(matcher)

React Testing Library๋Š” ๊ฑฐ์˜ E2E Test์ฒ˜๋Ÿผ ์‚ฌ์šฉ ๊ฐ€๋Šฅ โ†’ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์‚ฌ์šฉ์ž๊ฐ€ ์‹ค์ œ๋กœ ์‚ฌ์šฉํ•˜๋“ฏ์ด ํ…Œ์ŠคํŠธ

โš ๏ธ FE ํ…Œ์ŠคํŠธ โ‰  only React ์ปดํฌ๋„ŒํŠธ ํ…Œ์ŠคํŠธ ํ”„๋ก ํŠธ์—”๋“œ์—์„œ์˜ ํ…Œ์ŠคํŠธ๋Š” ์ข…๋ฅ˜๊ฐ€ ๋‹ค์–‘ํ•œ๋ฐ, ๊ทธ ์ค‘์—์„œ React ํ…Œ์ŠคํŠธ๋งŒ ํ•ด์„œ๋Š” ์•ˆ ๋จ UI๋Š” ๋‚ด๋ถ€์˜ ์ƒํƒœ๋ฅผ ํ‘œํ˜„ํ•ด ์ฃผ๋Š” ๋ฐฉ๋ฒ• ์ค‘์— ํ•˜๋‚˜์ผ ๋ฟ(React๊ฐ€ ๊ทธ๊ฒƒ์„ ์ง€์›ํ•˜๊ณ  ์žˆ์ง€๋งŒ) ์ผ์ผ์ด ํ™”๋ฉด๋งŒ ๊ฒ€์‚ฌํ•˜๋Š” ๊ฒƒ ๋ณด๋‹ค ๋‚ด๋ถ€ ๋ณธ์งˆ, ์ฆ‰ ์ƒํƒœ๋ฅผ ๊ฒ€์‚ฌํ•˜๋Š” ๊ฒƒ์ด ๋” ์‰ฌ์šธ ์ˆ˜ ์žˆ์Œ ์œ ์ง€๋ณด์ˆ˜๋ฅผ ๋•๊ธฐ ์œ„ํ•ด ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š”๋ฐ, ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž˜๋ชป ์ž‘์„ฑํ•˜๋ฉด(๋„ˆ๋ฌด ๋งŽ์€ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ๋“ฑ) ์˜คํžˆ๋ ค ์œ ์ง€๋ณด์ˆ˜๋ฅผ ์ €ํ•ดํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ฃผ์˜ํ•ด์•ผ ํ•จ

E2E Test

End To End ํ…Œ์ŠคํŠธ์˜ ์•ฝ์ž ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ํ๋ฆ„์„ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋๊นŒ์ง€ ํ…Œ์ŠคํŠธํ•˜๋Š” ๊ฒƒ (์ฐธ๊ณ ) ์นด์นด์˜ค์—”ํ„ฐํ…Œ์ธ๋จผํŠธ E2E ํ…Œ์ŠคํŠธ ๋„์ž… ๊ฒฝํ—˜๊ธฐ

ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์˜ˆ์‹œ

import { render } from '@testing-library/react';

test('Greeting', () => {
  render(<Greeting name="world" />);

  screen.getByText('Hello, world!'); // ํ…์ŠคํŠธ๋ฅผ ์ •ํ™•ํ•˜๊ฒŒ ๋ชจ๋‘ ์ž…๋ ฅํ•ด์•ผ ํ•จ, get์€ ์—†์œผ๋ฉด error

  screen.getByText(/Hello/); // ์ •๊ทœ ํ‘œํ˜„์‹์„ ํ™œ์šฉ, ์ฃผ๋กœ ์ด๋ ‡๊ฒŒ ํ…Œ์ŠคํŠธ ์ง„ํ–‰(ํ†ต๊ณผ ์—ฌ๋ถ€๊ฐ€ ์ค‘์š”ํ•˜๊ธฐ์—) 

  expect(screen.queryByText(/Hi/)).not.toBeInTheDocument(); // query๋Š” ์—†์œผ๋ฉด ์—†๋‹ค๊ณ  ๋ฐ˜ํ™˜ 
});

Last updated