jtwjs Dev Wiki
  • DEV_ROAD
    • πŸ’ͺ🏻 μƒμ‘΄ν•˜κΈ°
    • Week 1
      • 개발 ν™˜κ²½ μ„ΈνŒ…
      • νƒ€μž…μŠ€ν¬λ¦½νŠΈ
      • λ¦¬μ—‘νŠΈ
      • Testing Library
      • Parcel & ESLint
    • Week 2
      • JSX
      • Virtual DOM
    • Week 3
      • React Component
      • React State
    • Week 4
      • Express
      • Fetch API & CORS
      • React Hook
      • useRef & Custom Hook
    • Week 5
      • TDD
      • React Testing Library
      • MSW
      • Playwrite
      • Snapshot
    • Week 6
      • Separtion of Concerns
      • Principle
      • DI, (Dependency Injection)
      • Reflect-metadata
      • TSyringe
      • External Store
      • Follow Redux
      • usestore-ts
      • useSyncExternalStore
    • Week 7
      • Routing
      • Routes
      • Router
      • Navigation
    • Week 8
      • Design System
      • Style Basics
      • CSS-in-JS
      • Styled-Components
      • Global Style & Theme
    • Week 9
      • κ°œλ°œν•˜κΈ° μ „ μ€€λΉ„
      • μƒν’ˆ λͺ©λ‘ νŽ˜μ΄μ§€
      • μƒν’ˆ 상세 νŽ˜μ΄μ§€
      • μž₯λ°”κ΅¬λ‹ˆ νŽ˜μ΄μ§€
    • Week 10
      • 둜그인
      • λ‘œκ·Έμ•„μ›ƒ
      • νšŒμ›κ°€μž…
      • μ£Όλ¬Έ λͺ©λ‘ & μ£Όλ¬Έ 상세
    • Week 11
      • 배솑 정보 μž…λ ₯
      • ν¬νŠΈμ› 결제 μš”μ²­
      • 배솑 및 결제 정보 전달
    • Week 12
      • κ΄€λ¦¬μž μ›Ήμ‚¬μ΄νŠΈκ°œλ°œμ‹œμž‘
  • DEV_NOTE
    • TypeScript
      • 기본적 문법
        • Enum
        • λ‹€ν˜•μ„±
          • Untitled
        • ꡬ쑰적 타이핑
        • μ œλ„ˆλ¦­ νƒ€μž…
        • 컨디셔널 νƒ€μž…
        • ν•¨μˆ˜ λ©”μ„œλ“œ 타이핑
        • infer둜 νƒ€μž…μŠ€ν¬λ¦½νŠΈμ˜ μΆ”λ‘  직접 ν™œμš©
        • μž¬κ·€ νƒ€μž…
        • ν…œν”Œλ¦Ώ λ¦¬ν„°λŸ΄ νƒ€μž…
        • 좔가적인 νƒ€μž… 검사 satisfies μ—°μ‚°μž
        • νƒ€μž…μŠ€ν¬λ¦½νŠΈ 건망증
        • μ›μ‹œ μžλ£Œν˜•μ—λ„ λΈŒλžœλ”© 기법 μ‚¬μš© κ°€λŠ₯
        • νƒ€μž… 쒁히기
        • μœ μš©ν•œ νƒ€μž… λ§Œλ“€κΈ°
        • λ°μ½”λ ˆμ΄ν„° ν•¨μˆ˜
        • μ•°λΉ„μ–ΈνŠΈ 선언도 μ„ μ–Έ 병합이 λœλ‹€.
        • μ•°λΉ„μ–ΈνŠΈ 선언도 선언병합이 λœλ‹€.
    • Testing
      • Unit Testing
      • λ‹¨μœ„ ν…ŒμŠ€νŠΈμ˜ 두 λΆ„νŒŒ
      • 쒋은 λ‹¨μœ„ ν…ŒμŠ€νŠΈλ₯Ό κ΅¬μ„±ν•˜λŠ” 4λŒ€ μš”μ†Œ
      • ν…ŒμŠ€νŠΈ λŒ€μ—­κ³Ό 식별할 수 μžˆλŠ” λ™μž‘
      • λ‹¨μœ„ ν…ŒμŠ€νŠΈ μŠ€νƒ€μΌ
      • κ°€μΉ˜ μžˆλŠ” λ‹¨μœ„ ν…ŒμŠ€νŠΈλ₯Ό μœ„ν•œ λ¦¬νŒ©ν† λ§
      • 톡합 ν…ŒμŠ€νŠΈ
      • Cross Browsing Testing
      • κΈ°λŠ₯ ν…ŒμŠ€νŠΈ μ’…λ₯˜
      • React Testing Pattern
      • ν”„λ‘ νŠΈμ—”λ“œ ν…ŒμŠ€νŠΈ μž…λ¬Έ
        • ν…ŒμŠ€νŠΈ λ²”μœ„
        • λ‹¨μœ„ ν…ŒμŠ€νŠΈ 검증
        • Mock
        • UI μ»΄ν¬λ„ŒνŠΈ ν…ŒμŠ€νŠΈ
        • ν…ŒμŠ€νŠΈ 컀버리지
        • μ›Ή 톡합 ν…ŒμŠ€νŠΈ
        • MSW
        • μŠ€ν† λ¦¬λΆ
        • μ‹œκ°μ  νšŒκ·€ ν…ŒμŠ€νŠΈ
        • E2E ν…ŒμŠ€νŠΈ
        • Github Actions μ„€μ •
        • κΉƒν—ˆλΈŒ μ•‘μ…˜μ—μ„œ E2E
      • μ‹œν”„νŠΈ λ ˆν”„νŠΈ
        • ν…ŒμŠ€νŠΈ κΈ°λ³Έμ€‘μ˜ κΈ°λ³Έ
        • λ‹¨μœ„ ν…ŒμŠ€νŠΈ
        • μ½”λ“œ λ³΅μž‘λ„
        • λ¦¬νŒ©ν„°λ§
        • μ½”λ“œ 리뷰
        • 톡합 ν…ŒμŠ€νŠΈ νŒ¨ν„΄
        • μ‹œμŠ€ν…œ ν…ŒμŠ€νŠΈμ˜ μžλ™ν™”
        • 탐색적 ν…ŒμŠ€νŠΈ
      • Test Tip
      • vitest
      • playwright
      • Test Data Generator
      • MSW
    • Algorithm
      • coding test
      • Data Structure
    • Next.js
      • Data Fetching
      • Hydration
      • Next 13
      • Optimization
      • Next 15
    • Tailwind
      • Tailwind CSS
      • Theme
      • Directives
      • Tool
      • Design System
    • Storybook
      • Storybook
      • CSF3
      • CDD
      • Headless Component
    • Funtional Programming
      • ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ°
      • μ°Έμ‘° 투λͺ…μ„±
      • λΆ€μˆ˜νš¨κ³Ό
      • ν•¨μˆ˜ ν•©μ„±
      • μ œλ„ˆλ¦­ νƒ€μž… ν™œμš©ν•˜κΈ°
      • 암묡적 μž…μΆœλ ₯
      • μ•‘μ…˜κ³Ό 계산, 데이터
      • κ³„μΈ΅ν˜• 섀계
      • 호좜 κ·Έλž˜ν”„
      • ν•¨μˆ˜ν˜• 섀계
      • λΆˆλ³€μ„±
      • 일급 ν•¨μˆ˜
      • ν•¨μˆ˜ν˜• 도ꡬ
    • Git
      • Github Actions
      • Conflict
      • Branch μ „λž΅
    • Contents Format
      • Audio
    • 3D Graphic
      • 3D keyword
      • Three.js
      • Geometry
      • Material
      • Light
      • Camera
      • Decal
      • Rotation
      • Text
      • Shadow
      • Fog
      • Post Processing
      • Animation
      • Math
        • Vector Space
        • λ²‘ν„°μ˜ μ—°μ‚°
        • νšŒμ „ 계산
      • 3D 컨텐츠가 λ§Œλ“€μ–΄μ§€λŠ” κ³Όμ •
      • R3F
      • Env
      • Scene
      • Transform
      • R3F
      • Interaction & Raycast
      • Rendering Algorithnm
      • Blender
      • Blender
    • Accessibility
      • μ ‘κ·Όμ„±μ΄λž€
    • Interactive Web
      • Parallax
      • Canvas
      • requestAnimationFrame
      • Effect
      • HSL
      • React.js + Canvas
      • Matter.js
    • AWS
      • DevOps
      • Amplify
      • S3
      • ν΄λΌμš°λ“œ μ»΄ν“¨νŒ…
        • μ˜¨ν”„λ ˆλ―ΈμŠ€μ™€ ν΄λΌμš°λ“œ
        • ν΄λΌμš°λ“œ λ„μž…νš¨κ³Ό
        • ν΄λΌμš°λ“œ μ»΄ν“¨νŒ…μ˜ λ²”μœ„
        • μ»΄ν“¨νŒ… μ˜΅μ…˜
          • EC2 - Virtual Machin
          • ECS, EKS - Container
          • Lambda - Serverless
        • λ„€νŠΈμ›Œν¬ 가상화
        • μŠ€ν† λ¦¬μ§€
        • λ°μ΄ν„°λ² μ΄μŠ€
        • 데이터 μˆ˜μ§‘
        • λ¨Έμ‹  λŸ¬λ‹ μ˜μ—­
        • IoT μ˜μ—­
        • 블둝체인 μ˜μ—­
      • ν΄λΌμš°λ“œ μ•„ν‚€ν…μ²˜ 섀계
    • Network
      • Web Server & WAS
    • System Design
      • System Design
      • Component
      • μ˜μ‘΄μ„±μ„ λ°°μ œν•œ 개발
      • Error Handling
      • Architecture
        • λͺ¨λ…Έλ‘œν‹± μ•„ν‚€ν…μ²˜
        • Clean Architecture
        • Layered Architecture
        • 이벀트 기반 μ•„ν‚€ν…μ²˜
      • 상황을 νŒŒμ•…ν•˜λŠ” 메타인지
      • 쀑볡 문제 ν•΄κ²°ν•˜κΈ°
      • Monorepo Arhitecture
        • λͺ¨λ…Έλ ˆν¬ 운영과 νŠΈλŸ¬λΈ”μŠˆνŒ…
        • Module Federation
      • μ½”λ“œ 병λͺ©μ§€μ 
      • API λŒ€μ‘
      • 곡톡 μ½”λ“œ
      • Infra ꡬ좕
      • λͺ¨λ“ˆ 기반의 개발 방식
      • Design System
        • μ΅œμ†Œ μˆ˜μ€€μ˜ μ•„ν‚€ν…μ²˜ μ„€μ •
        • 더 효율적인 λ””μžμΈμ‹œμŠ€ν…œ λ§Œλ“€κΈ°
        • λ””μžμΈ μ‹œμŠ€ν…œκ³Ό UI 라이브러리 λͺ©μ 
        • λ””μžμΈ 토큰
      • 효율적인 업무
        • 업무 ν”„λ‘œμ„ΈμŠ€ 병λͺ© νŒŒμ•…
      • Clean Code
      • Design Pattern
        • CQRS Pattern
        • Strangler Fig Pattern
        • λ°μ½”λ ˆμ΄ν„° νŒ¨ν„΄
        • μ»€λ§¨λ“œ νŒ¨ν„΄
        • μ „λž΅ νŒ¨ν„΄
        • μ˜΅μ €λ²„ νŒ¨ν„΄
      • A/B ν…ŒμŠ€νŒ…
      • λŒ€κ·œλͺ¨ λ¦¬μ—‘νŠΈ μ›Ήμ•± 개발
        • λ³΅μž‘μ„± 관리
        • λͺ¨λ“ˆμ„±
        • μ„±λŠ₯
        • λ””μžμΈ μ‹œμŠ€ν…œ
        • 데이터 패칭
        • μƒνƒœ 관리
        • κ΅­μ œν™”
        • μ½”λ“œ μ‘°μ§ν™”ν•˜κΈ°
        • κ°œμΈν™” A/B ν…ŒμŠ€νŒ…
        • ν™•μž₯ κ°€λŠ₯ν•œ μ›Ή μ•„ν‚€ν…μ²˜
        • ν…ŒμŠ€νŒ…
        • 툴링
        • 기술적 λ§ˆμ΄κ·Έλ ˆμ΄μ…˜
        • νƒ€μž…μŠ€ν¬λ¦½νŠΈ
        • λΌμš°νŒ…
        • μ‚¬μš©μž 쀑심 API λ””μžμΈ
        • λ¦¬μ•‘νŠΈ 미래
    • Performance
      • React DevTools
      • Component μ΅œμ ν™”
      • Page Load
      • API
    • MFA
      • MSA
      • MFA λ„μž…ν•˜κΈ°
      • Monorepo
        • Monorepo Tool
        • Yarn Berry Workspace
        • Turborepo
      • MFA Composition
      • SPA 톡합
      • Design System
      • Package Manager
        • Yarn
        • pnpm
      • Transpiler & Bundler
        • Babel
        • Rollup
        • esbuild
        • swc
        • Webpack
        • Vite
      • 뢄해와 톡합을 μœ„ν•œ μ—¬λŸ¬ 기술 비ꡐ
    • State Management
      • Zustand
    • React v18
      • Automatic batching
      • Suspense
      • Transition
    • SEO
      • Search Engine Optimization
      • Open Graph Element
      • Metadata
    • FE Develop
      • Scrubbing
      • Clipboard
    • Refactoring
      • λ¦¬νŒ©ν† λ§ 깊게 듀여닀보기
      • κΈ΄ μ½”λ“œ 쑰각내기
      • νƒ€μž… μ½”λ“œ μ²˜λ¦¬ν•˜κΈ°
      • μœ μ‚¬ν•œ μ½”λ“œ μœ΅ν•©ν•˜κΈ°
      • 데이터 보호
      • μ½”λ“œ μΆ”κ°€ 및 제거
    • OAuth 2.0
    • Analytics
      • Mixpanel
    • ETC
      • VSCode
    • React Hook In Action
      • useContext & Provider
      • μ»€μŠ€ν…€ ν›…
      • μ½”λ“œ λΆ„ν• ν•˜κΈ° with Suspense, lazy
      • Suspense와 이미지 μ μž¬ν•˜κΈ°
      • useTransition, uesDeferredValue
      • SuspenseList
Powered by GitBook
On this page
  • Mock 객체λ₯Ό μ‚¬μš©ν•˜λŠ” 이유
  • λͺ© 객체 μš©μ–΄
  • Stub
  • Spy
  • Jest의 μš©μ–΄ ν˜Όλž€
  • Jest둜 λͺ© λͺ¨λ“ˆμ„ ν™œμš©ν•˜μ—¬ μŠ€ν… κ΅¬ν˜„ν•˜κΈ°
  • μ›Ή API λͺ© 객체 기초
  • μ›Ή APIλ₯Ό ν΄λΌμ΄μ–ΈνŠΈ μŠ€ν… κ΅¬ν˜„
  • ν”½μŠ€μ²˜
  • λͺ© 객체 생성 ν•¨μˆ˜
  • λͺ© ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜λŠ” 슀파이
  • μ‹€ν–‰λλŠ”μ§€ κ²€μ¦ν•˜κΈ°
  • μ‹€ν–‰ 횟수 검증
  • μ‹€ν–‰ μ‹œ 인수 검증
  • μ‹€ν–‰ μ‹œ μΈμˆ˜κ°€ 객체일 λ•Œμ˜ 검증
  • ν…ŒμŠ€νŠΈ μ€€λΉ„
  • ν˜„μž¬ μ‹œκ°μ— μ˜μ‘΄ν•˜λŠ” ν…ŒμŠ€νŠΈ
  • ν…ŒμŠ€νŠΈ μ„€μ •κ³Ό 파기
  1. DEV_NOTE
  2. Testing
  3. ν”„λ‘ νŠΈμ—”λ“œ ν…ŒμŠ€νŠΈ μž…λ¬Έ

Mock

Mock 객체λ₯Ό μ‚¬μš©ν•˜λŠ” 이유

  • ν…ŒμŠ€νŠΈλŠ” μ‹€μ œ μ‹€ν–‰ ν™˜κ²½κ³Ό μœ μ‚¬ν• μˆ˜λ‘ μž¬ν˜„μ„±μ΄ λ†’λ‹€.

  • ν•˜μ§€λ§Œ μž¬ν˜„μ„±μ„ 높이닀보면 μ‹€ν–‰ μ‹œκ°„μ΄ 였래 κ±Έλ¦¬κ±°λ‚˜ ν™˜κ²½ ꡬ좕이 μ–΄λ €μ›Œμ§€λŠ” κ²½μš°κ°€ μžˆλ‹€.

    • λŒ€ν‘œμ μœΌλ‘œ μ›Ή API 데이터λ₯Ό λ‹€λ€„μ•Όν•˜λŠ” 경우 λ„€νŠΈμ›Œν¬ 였λ₯˜μ™€κ°™μ΄ μ œμ–΄ν•  수 μ—†λŠ” λΆ€λΆ„μ—μ„œ μ‹€νŒ¨ν•  수 있음

  • ν…ŒμŠ€νŠΈν•˜λŠ” λŒ€μƒμ€ μ›Ή API μžμ²΄κ°€ μ•„λ‹Œ 응닡 데이터에 λŒ€ν•œ μ²˜λ¦¬λΌλŠ”κ²ƒμ„ λͺ…심

  • μ‹€μ œ API 응닡값 λŒ€μ‹  μ‚¬μš©ν•˜λŠ” 것이 λͺ© 객체이닀.

  • λͺ© 객체λ₯Ό μ‚¬μš©ν•˜λ©΄ ν…ŒμŠ€νŠΈκ°€ μ–΄λ €μš΄ 뢀뢄을 ν…ŒμŠ€νŠΈλ₯Ό κ°€λŠ₯ν•˜κ²Œ ν•˜κ³  λ”μš± 효율적인 ν…ŒμŠ€νŠΈκ°€ κ°€λŠ₯ν•΄μ§„λ‹€.

λͺ© 객체 μš©μ–΄

  • stub, spy 등은 λͺ© 객체λ₯Ό 상황에 따라 μ„ΈλΆ„ν™”ν•œ 객체의 λͺ…μΉ­

  • 개발 언어에 상관없이 ν…ŒμŠ€νŠΈ μžλ™ν™” κ΄€λ ¨ λ¬Έν—ˆμ—μ„œ μ •μ˜ν•œ μš©μ–΄

Stub

μŠ€ν…μ€ 주둜 λŒ€μ—­μœΌλ‘œ μ‚¬μš©ν•œλ‹€. 1) μ˜μ‘΄μ€‘μΈ μ»΄ν¬λ„ŒνŠΈμ˜ λŒ€μ—­ 2) μ •ν•΄μ§„ 값을 λ°˜ν™˜ν•˜λŠ” μš©λ„ 3) ν…ŒμŠ€νŠΈ λŒ€μƒμ— ν• λ‹Ήν•˜λŠ” μž…λ ₯κ°’

즉, ν…ŒμŠ€νŠΈ μ½”λ“œμ—μ„œ μ‹€μ œλ‘œ μ˜μ‘΄ν•˜λŠ” λ°μ΄ν„°λ‚˜ κΈ°λŠ₯을 λŒ€μ²΄ν•˜λŠ” 더미 데이터λ₯Ό λ°˜ν™˜ν•˜λŠ” μ—­ν• 

  • ν…ŒμŠ€νŠΈ λŒ€μƒμ΄ μ˜μ‘΄μ€‘μΈ μ»΄ν¬λ„ŒνŠΈμ— ν…ŒμŠ€νŠΈν•˜κΈ° μ–΄λ €μš΄ 뢀뢄이 μžˆμ„ λ•Œ

  • μ›Ή API에 μ˜μ‘΄μ€‘μΈ λŒ€μƒμ„ ν…ŒμŠ€νŠΈν•˜λŠ” 경우

  • "μ›Ή APIμ—μ„œ 이런 값을 λ°˜ν™˜λ°›μ•˜μ„ λ•ŒλŠ” μ΄λ ‡κ²Œ μž‘λ™ν•΄μ•Ό ν•œλ‹€." 와 같은 ν…ŒμŠ€νŠΈμ— μŠ€ν…μ„ μ‚¬μš©ν•œλ‹€.

Spy

μŠ€νŒŒμ΄λŠ” 주둜 κΈ°λ‘ν•˜λŠ” μš©λ„

1) ν•¨μˆ˜λ‚˜ λ©”μ„œλ“œμ˜ 호좜 기둝

2) 호좜된 νšŸμˆ˜λ‚˜ μ‹€ν–‰ μ‹œ μ‚¬μš©ν•œ 인수 기둝

3) ν…ŒμŠ€νŠΈ λŒ€μƒμ˜ 좜λ ₯ 확인

  • ν…ŒμŠ€νŠΈ λŒ€μƒ μ™ΈλΆ€μ˜ 좜λ ₯을 검증할 λ•Œ μ‚¬μš©ν•œλ‹€.

  • 인수둜 받은 콜백 ν•¨μˆ˜λ₯Ό κ²€μ¦ν•˜λŠ” 것

    • μ½œλ°±ν•¨μˆ˜κ°€ μ‹€ν–‰λœ 횟수

    • μ‹€ν–‰ μ‹œ μ‚¬μš©ν•œ 인수

    • μ˜λ„ν•œ λŒ€λ‘œ 콜백이 ν˜ΈμΆœλλŠ”μ§€ 검증

Jest의 μš©μ–΄ ν˜Όλž€

  • μ œμŠ€νŠΈλŠ” μŠ€ν…, 슀파이λ₯Ό κ΅¬ν˜„ν•  λ•Œ jest.mock(λͺ© λͺ¨λ“ˆ) ν˜Ήμ€jest.fn, jest.spyOn(λͺ© ν•¨μˆ˜) λΌλŠ” APIλ₯Ό μ‚¬μš©ν•œλ‹€.

  • μ œμŠ€νŠΈλŠ” 이λ₯Ό κ΅¬ν˜„ν•œ ν…ŒμŠ€νŠΈ λŒ€μ—­μ„ λͺ© 객체라고 λΆ€λ₯΄λŠ” λ“± xUnit ν…ŒμŠ€νŠΈ νŒ¨ν„΄μ—μ„œ μ •μ˜ν•œ μš©μ–΄μ™€λŠ” λ‹€λ₯Έ 뢀뢄이 많음

  • μŠ€ν… ν˜Ήμ€ μŠ€νŒŒμ΄λ‘œμ„œ μ‚¬μš©ν•˜λŠ” λͺ…ν™•ν•œ μ΄μœ κ°€ μžˆμ„ λ•Œλ₯Ό μ œμ™Έν•˜κ³ λŠ” λͺ© 객체라고 λΆ€λ₯΄μž.

Jest둜 λͺ© λͺ¨λ“ˆμ„ ν™œμš©ν•˜μ—¬ μŠ€ν… κ΅¬ν˜„ν•˜κΈ°

  • λ‹¨μœ„ ν…ŒμŠ€νŠΈλ‚˜ 톡합 ν…ŒμŠ€νŠΈλ₯Ό μž‘μ„±ν•  λ•Œ κ΅¬ν˜„μ΄ μ™„μ„±λ˜μ–΄ μžˆμ§€ μ•Šκ±°λ‚˜ μˆ˜μ •μ΄ ν•„μš”ν•œ λͺ¨λ“ˆμ— μ˜μ‘΄μ€‘μΈ κ²½μš°κ°€ μžˆλ‹€

  • μ΄λ•Œ λͺ© λͺ¨λ“ˆλ‘œ λŒ€μ²΄ν•˜λ©΄ ν…ŒμŠ€νŠΈν•  수 μ—†μ—ˆλ˜ λŒ€μƒμ„ ν…ŒμŠ€νŠΈ κ°€λŠ₯ν•˜κ²Œ ν•œλ‹€.

export function greet(name: string) {
  return `Hello ${name}.`;
}
export function sayGoodBye(name: string) {
  throw new Error("λ―Έκ΅¬ν˜„")
}
import { greet } from './greet';

jest.mock("./greet"); // jest.mock이 ν…ŒμŠ€νŠΈ 전에 ν˜ΈμΆœλ˜λ©΄μ„œ ν…ŒμŠ€νŠΈν•  λͺ¨λ“ˆμ„ λŒ€μ²΄ν•¨

test("인사말을 λ°˜ν™˜ν•˜μ§€ μ•ŠλŠ”λ‹€(μ›λž˜ κ΅¬ν˜„κ³Ό λ‹€λ₯΄κ²Œ)", () => {
  expect(greet("woong")).toBe(undefined)
})

λͺ¨λ“ˆμ„ μŠ€ν…μœΌλ‘œ λŒ€μ²΄ν•˜κΈ°

  • jest.mock 의 두 번째 μΈμˆ˜μ—λŠ” λŒ€μ²΄ν•  ν•¨μˆ˜λ₯Ό κ΅¬ν˜„ν•  수 μžˆλ‹€.

  • λͺ¨λ“ˆμ˜ 일뢀λ₯Ό ν…ŒμŠ€νŠΈμ—μ„œ λŒ€μ²΄ν•˜λ©΄ 의쑴 쀑인 λͺ¨λ“ˆμ˜ ν…ŒμŠ€νŠΈκ°€ 어렡더라도 ν…ŒμŠ€νŠΈκ°€ κ°€λŠ₯ν•˜κ²Œ λ§Œλ“€ 수 μžˆλ‹€.

import { greet, sayGoodBye } from './greet';

// ./greet λͺ¨λ“ˆμ„ λͺ¨λ‘ λŒ€μ²΄ν•˜κ²Œ λ˜μ–΄ λ”°λ‘œ μ„€μ •ν•˜μ§€ μ•ŠμœΌλ©΄ undefinedλ₯Ό λ°˜ν™˜ν•˜κ²Œ λœλ‹€.
jest.mock("./greet", () => ({
  sayGoodBye: (name: string) => `Good bye, ${name}`,
}))

test("μž‘λ³„ 인사λ₯Ό λ°˜ν™˜ν•œλ‹€(μ›λž˜ κ΅¬ν˜„κ³Ό λ‹€λ₯΄κ²Œ)", () => {
  const message = `${sayGoodBye("woong")} See you.`;
  expect(message).toBe("Good bye. woong See you.");
})

λͺ¨λ“ˆ 일뢀λ₯Ό μŠ€ν…μœΌλ‘œ λŒ€μ²΄ν•˜κΈ°

  • jest.requireActual ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜λ©΄ μ›λž˜ λͺ¨λ“ˆμ˜ κ΅¬ν˜„μ„ import ν•  수 μžˆλ‹€.

import { greet, sayGoodBye } from './greet';

jest.mock("./greet", () => ({
  ...jest.requireActual('./greet'),
  sayGoodBye: (name: string) => `Good bye, ${name}.`
}))

test("인사말을 λ°˜ν™˜ν•œλ‹€.(μ›λž˜ κ΅¬ν˜„κ³Ό λ™μΌν•˜κ²Œ)", () => {
  expect(greet("woong")).toBe("Hello woong");
})

라이브러리 λŒ€μ²΄ν•˜κΈ°

  • μˆ˜μ •μ΄ ν•„μš”ν•œ λͺ¨λ“ˆμ˜ 일뢀λ₯Ό λŒ€μ²΄ν•˜λŠ” 방법

  • μ‹€λ¬΄μ—μ„œλŠ” 라이브러리λ₯Ό λŒ€μ²΄ν•  λ–„ λͺ© λͺ¨λ“ˆμ„ κ°€μž₯ 많이 μ‚¬μš©ν•œλ‹€.

// next/router 의쑴 λͺ¨λ“ˆ λŒ€μ‹  next-router-mock μ΄λΌλŠ” 라이브러리λ₯Ό 적용
jest.mock("next/router", () => require("next-router-mock"));

μ›Ή API λͺ© 객체 기초

  • μ›Ή μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œλŠ” μ›Ή API μ„œλ²„μ™€ ν†΅μ‹ ν•˜μ—¬ 데이터λ₯Ό μ·¨λ“ν•˜κ³  κ°±μ‹ ν•˜λŠ” μž‘μ—…μ€ ν•„μˆ˜

  • ν…ŒμŠ€νŠΈν•  λ•ŒλŠ” μ›Ή API κ΄€λ ¨ μ½”λ“œλ₯Ό μ›Ή API ν΄λΌμ΄μ–ΈνŠΈμ˜ λŒ€μ—­μΈ μŠ€ν…μœΌλ‘œ λŒ€μ²΄ν•˜μ—¬ ν…ŒμŠ€νŠΈλ₯Ό μž‘μ„±ν•œλ‹€.

  • μŠ€ν…μ΄ μ‹€μ œ 응닡은 μ•„λ‹ˆμ§€λ§Œ 응닡 μ „ν›„μ˜ κ΄€λ ¨ μ½”λ“œλ₯Ό 검증할 λ•Œ μœ μš©ν•˜κ²Œ μ‚¬μš© κ°€λŠ₯ν•˜λ‹€.

  • μ›Ή API μ„œλ²„κ°€ μ—†μœΌλ©΄ APIλ₯Ό 호좜이 ν¬ν•¨λœ λ‘œμ§μ€ ν…ŒμŠ€νŠΈκ°€ λΆˆκ°€λŠ₯ν•˜λ‹€.

    • ν•΄λ‹Ή API 호좜 뢀뢄을 μŠ€ν…μœΌλ‘œ λŒ€μ²΄ν•˜λ©΄ μ‹€μ œ μ„œλ²„μ˜ 응닡 μ—¬λΆ€ 상관없이 데이터 취득과 κ΄€λ ¨λœ λ‘œμ§μ„ ν…ŒμŠ€νŠΈν•  수 μžˆλ‹€.

API μ„œλ²„λŠ” MSW(Mock Service Worker)둜 λŒ€μ²΄ν•΄μ„œ μ‚¬μš©ν•˜μž.

μ•„λž˜ λ‚΄μš©λ“€μ€ κ·Έλƒ₯ 이런게 μžˆκ΅¬λ‚˜ ν•˜κ³  γ…Œγ…Œγ…Œ

import { getMyProfile } from "../fetchers";

export async function getGreet() {
  const data = await getMyProfile();
  if (!data.name) {
    return `Hello, anonymouse user!`;
  }
  return `Hello, ${data.name}!`;
}

μ›Ή APIλ₯Ό ν΄λΌμ΄μ–ΈνŠΈ μŠ€ν… κ΅¬ν˜„

  • νƒ€μž…μŠ€ν¬λ¦½νŠΈμ™€ 상성이 쒋은 jest.spyOn 을 μ‚¬μš©ν•΄λ³΄μž.

import * as Fetchers from "./fetchers";
jest.mock("./fetchers");

// jest.spyOn으둜 ν…ŒμŠ€νŠΈν•  객체λ₯Ό λŒ€μ²΄ν•œλ‹€. (ν…ŒμŠ€νŠΈν•  객체 -> Fetchers)
// jest.spyOn(ν…ŒμŠ€νŠΈν•  객체, ν…ŒμŠ€νŠΈν•  ν•¨μˆ˜ 이름); 
// *ν…ŒμŠ€νŠΈν•  λŒ€μƒμ— μ •μ˜λ˜μ§€ μ•Šμ€ ν•¨μˆ˜ 이름을 μ§€μ •ν•˜λ©΄ νƒ€μž…μ˜€λ₯˜ λ°œμƒ
jest.spyOn(Fetcehrs, "getMyProfile")

데이터 취득 성곡을 μž¬ν˜„ν•œ ν…ŒμŠ€νŠΈ

  • 데이터 취득이 μ„±κ³΅ν–ˆμ„ λ•Œ(resolve) μ‘λ‹΅μœΌλ‘œ κΈ°λŒ€ν•˜λŠ” 객체λ₯Ό mockResolvedValueOnce 에 μ§€μ •

  • μ—¬κΈ°μ„œ μ§€μ •ν•œ 객체도 νƒ€μž…μ‹œμŠ€ν…œμ΄ 적용된 μƒνƒœμ΄λ―€λ‘œ μœ μ§€λ³΄μˆ˜ μˆ˜μ›”

test("데이터 취득 μ„±κ³΅μ‹œ: μ‚¬μš©μž 이름이 μ—†λŠ” 경우", async () => {
  // apiκ°€ resolve됐을 λ•Œμ˜ 값을 μž¬ν˜„
  jest.spyOn(Fetchers, "getMyProfile").mockResolvedValueOnce({
    id: "....",
    eamil: "...",
  });
  await expect(getGreet()).resolves.toBe("Hello, anonymouse user!");
})

test("데이터 취득 μ„±κ³΅μ‹œ: μ‚¬μš©μž 이름이 μžˆλŠ” 경우", async () => {
  // apiκ°€ resolve됐을 λ•Œμ˜ 값을 μž¬ν˜„
  jest.spyOn(Fetchers, "getMyProfile").mockResolvedValueOnce({
    id: "....",
    eamil: "...",
    name: "woong",
  });
  await expect(getGreet()).resolves.toBe("Hello, woong!");
})

데이터 취득 μ‹€νŒ¨λ₯Ό μž¬ν˜„ν•œ ν…ŒμŠ€νŠΈ

export function getMyProfile(): Promise<Profile> {
  return fetch("...").then(async (res) => {
    const data = await res.json();
    if (!res.ok) {
      //200λ²ˆλŒ€ μ™Έμ˜ 응닡인 경우
      throw data;
    }
    return data;
  })
}

// 였λ₯˜ 객체
export const httpError: HttpError = {
  err: { message: "internal server error" },
};
  • 였λ₯˜ 객체λ₯Ό mockRejectedValueOnce 인수둜 getMyProfile ν•¨μˆ˜μ˜ rejectλ₯Ό μž¬ν˜„ν•˜λŠ” μŠ€ν…μ„ κ΅¬ν˜„

test("데이터 취득 μ‹€νŒ¨μ‹œ", async () => {
  jest.spyOn(Fetchers, "getMyProfile").mockRejectedValueOnce(httpError)
  await expect(getGreet()).rejects.toMatchObject({
    err: {message: "internal server error" },
  })
})

test("데이터 취득 μ‹€νŒ¨μ‹œ 였λ₯˜κ°€ λ°œμƒν•œ 데이터와 ν•¨κ»˜ μ˜ˆμ™Έκ°€ throwλœλ‹€.", async () => {
  expect.assertions(1);
  jest.spyOn(Fetchers, "getMyProfile").mockRejectedValueOnce(httpError)
  try {
    await getGreet();
  } catch (err) {
    expect(err).toMatchObject(httpError);
  }
})

ν”½μŠ€μ²˜

응닡을 μž¬ν˜„ν•˜κΈ° μœ„ν•œ ν…ŒμŠ€νŠΈμš© 데이터λ₯Ό 의미

λͺ© 객체 생성 ν•¨μˆ˜

ν…ŒμŠ€νŠΈμ— ν•„μš”ν•œ 섀정을 μ΅œλŒ€ν•œ 적은 λ§€κ°œλ³€μˆ˜λ‘œ ꡐ체할 수 있게 λ§Œλ“œλŠ” μœ ν‹Έλ¦¬ν‹° ν•¨μˆ˜

  • ν…ŒμŠ€νŠΈν•  λ•Œλ§ˆλ‹€ jest.spyOn 을 μž‘μ„±ν•˜μ§€ μ•Šμ•„λ„ λ˜μ–΄ μ½”λ“œκ°€ 깔끔해진닀.

λͺ© ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜λŠ” 슀파이

  • 제슀트의 λͺ© ν•¨μˆ˜λ‘œ 슀파이λ₯Ό κ΅¬ν˜„ν•˜λŠ” 방법

  • μŠ€νŒŒμ΄λŠ” ν…ŒμŠ€νŠΈ λŒ€μƒμ— λ°œμƒν•œ μž…μΆœλ ₯을 κΈ°λ‘ν•˜λŠ” 객체

  • μŠ€νŒŒμ΄μ— 기둝된 값을 κ²€μ¦ν•˜μ—¬ μ˜λ„ν•œ λŒ€λ‘œ κΈ°λŠ₯이 μž‘λ™ν•˜λŠ”μ§€ ν…ŒμŠ€νŠΈν•  수 있음

μ‹€ν–‰λλŠ”μ§€ κ²€μ¦ν•˜κΈ°

  • jest.fn μ‚¬μš©ν•΄μ„œ λͺ© ν•¨μˆ˜λ₯Ό μž‘μ„±

  • μž‘μ„±ν•œ λͺ© ν•¨μˆ˜λŠ” ν…ŒμŠ€νŠΈ μ½”λ“œμ—μ„œ ν•¨μˆ˜λ‘œ μ‚¬μš©ν•˜λ©° tobeCalled 맀처λ₯Ό μ‚¬μš©ν•˜λ©΄ μ‹€ν–‰ μ—¬λΆ€ 검증 κ°€λŠ₯

test("λͺ© ν•¨μˆ˜κ°€ 싀행됐닀.", () => {
  const mockFn = jest.fn();
  mocFn();
  expect(mockFn).toBeCalled();
})

test("λͺ© ν•¨μˆ˜κ°€ μ‹€ν–‰λ˜μ§€ μ•Šμ•˜λ‹€.", () => {
  const mockFn = jest.fn();
  expect(mockFn).not.toBeCalled();
})

μ‹€ν–‰ 횟수 검증

  • λͺ© ν•¨μˆ˜λŠ” μ‹€ν–‰ 횟수λ₯Ό κΈ°λ‘ν•œλ‹€.

  • toHaveBeenCalledTimes 맀처λ₯Ό μ‚¬μš©ν•˜λ©΄ ν•¨μˆ˜κ°€ λͺ‡ 번 ν˜ΈμΆœλλŠ”μ§€ 검증

test("λͺ© ν•¨μˆ˜λŠ” μ‹€ν–‰ 횟수λ₯Ό κΈ°λ‘ν•œλ‹€", () => {
  const mockFn = jest.fn();
  mockFn();
  expect(mockFn).toHaveBeenCalledTimes(1);
  mockFn();
  expect(mockFn).toHaveBeenCalledTimes(2);
})

μ‹€ν–‰ μ‹œ 인수 검증

  • λͺ© ν•¨μˆ˜λŠ” μ‹€ν–‰ μ‹œ μΈμˆ˜λ„ 기둝

    • toHaveBeenCalledWith 맀처λ₯Ό μ‚¬μš©

  • λͺ© ν•¨μˆ˜λŠ” λ‹€λ₯Έ ν•¨μˆ˜ μ•ˆμ— μž‘μ„±ν•  μˆ˜λ„ μžˆλ‹€.

test("λͺ© ν•¨μˆ˜λŠ” μ•ˆμ—μ„œλ„ μ‹€ν–‰ν•  수 μžˆλ‹€.", () => {
  const mockFn = jest.fn();
  function greet() {
    mockFn();
  }
  greet();
  expect(mockFn).toHaveBeenCalledTimes(1);
})
test("λͺ© ν•¨μˆ˜λŠ” μ‹€ν–‰ μ‹œ 인수λ₯Ό κΈ°λ‘ν•œλ‹€", () => {
  const mockFn = jest.fn();
  function greet(message: string) {
    mockFn(message); // 인수λ₯Ό λ°›μ•„ μ‹€ν–‰
  }
  greet("hello"); // "hello"λ₯Ό 인수둜 μ‹€ν–‰λœκ²ƒμ΄ mockFn에 κΈ°λ‘λœλ‹€.
  expect(mockFn).toHaveBeenCalledWith("hello");
})

μ‹€ν–‰ μ‹œ μΈμˆ˜κ°€ 객체일 λ•Œμ˜ 검증

  • μΈμˆ˜κ°€ λ¬Έμžμ—΄ 같은 μ›μ‹œν˜•μ΄ μ•„λ‹Œ λ°°μ—΄μ΄λ‚˜ 객체일 λ•Œλ„ 검증이 κ°€λŠ₯ν•˜λ‹€.

  • expect.objectContaining λΌλŠ” 보쑰 ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜λ©΄ 객체의 μΌλΆ€λ§Œ 검증할 수 μžˆλ‹€.

    • 객체가 λ„ˆλ¬΄ 크면 μΌλΆ€λ§Œ 검증할 수 밖에 μ—†λ‹€.

test("expect.objectContainingλ₯Ό μ‚¬μš©ν•œ λΆ€λΆ„ 검증", () => {
  const mockFn = jest.fn();
  checkConfig(mockFn);
  expect(mockFn).toHaveBeenCalledWith(
    expect.objectContaining({
      feature: { spy: true },
    })
  )
})

μ‹€λ¬΄μ—μ„œλŠ” '폼에 νŠΉμ • μΈν„°λ ‰μ…˜μ΄ λ°œμƒν•˜λ©΄ μ‘λ‹΅μœΌλ‘œ 받은 값은 OO이닀' 같은 ν…ŒμŠ€νŠΈλ₯Ό 자주 μž‘μ„±ν•˜κ²Œ λœλ‹€.

ν…ŒμŠ€νŠΈ μ€€λΉ„

  • μž…λ ₯ 값을 λ™μ μœΌλ‘œ 생성할 수 μžˆλŠ” νŒ©ν† λ¦¬ ν•¨μˆ˜

function inputFactory(input?: Partial<ArticleInput>) {
  return {
    tags: ["testing"],
    title: "νƒ€μž…μŠ€ν¬λ¦½νŠΈ ν…ŒμŠ€νŒ… μž‘μ„±λ²•",
    body: "...",
    ...input,
  }
}

const input = inputFactory(); //μœ νš¨μ„± 검사λ₯Ό ν†΅κ³Όν•˜λŠ” 객체 λ°˜ν™˜
const input = inputFactory({title: "", body: ""}); // μœ νš¨μ„± 검사에 ν†΅κ³Όν•˜μ§€ λͺ»ν•˜λŠ” 객체 λ°˜ν™˜

ν˜„μž¬ μ‹œκ°μ— μ˜μ‘΄ν•˜λŠ” ν…ŒμŠ€νŠΈ

  • ν˜„μž¬ μ‹œκ°μ— μ˜μ‘΄ν•˜λŠ” 둜직이 ν…ŒμŠ€νŠΈ λŒ€μƒμ— 포함됐닀면 ν…ŒμŠ€νŠΈ κ²°κ³Όκ°€ μ‹€ν–‰ μ‹œκ°μ— μ˜μ‘΄ν•˜κ²Œ 됨

  • νŠΉμ • μ‹œκ°„λŒ€μ—λŠ” CI의 ν…ŒμŠ€νŠΈ μžλ™ν™”κ°€ μ‹€νŒ¨ν•˜λŠ” λΆˆμ•ˆμ •ν•œ ν…ŒμŠ€νŠΈκ°€ λœλ‹€.

  • μ΄λ•Œ ν…ŒμŠ€νŠΈ μ‹€ν–‰ ν™˜κ²½μ— ν˜„μž¬ μ‹œκ°μ„ κ³ μ •ν•˜λ©΄ 항상 λ™μΌν•œ ν…ŒμŠ€νŠΈ κ²°κ³Όλ₯Ό 얻을 수 μžˆλ‹€.

export function greetByTime() {
  const hour = new Date().getHours();
  if (hour < 12) {
    return "good morning"
  } else if (hour < 18) {
    return "good afternoon",
  } else { 
    return "good evening"
  }
}

ν˜„μž¬ μ‹œκ° κ³ μ •ν•˜κΈ°

  • ν…ŒμŠ€νŠΈ μ‹€ν–‰ ν™˜κ²½μ˜ ν˜„μž¬ μ‹œκ°μ„ μž„μ˜μ˜ μ‹œκ°μœΌλ‘œ κ³ μ •ν•˜λ €λ©΄ λ‹€μŒκ³Ό 같은 ν•¨μˆ˜ μ‚¬μš©

    • jest.useFakeTimers : μ œμŠ€νŠΈμ— κ°€μ§œ 타이머λ₯Ό μ‚¬μš©ν•˜λ„λ‘ μ§€μ‹œ

    • jest.setSystemTime : κ°€μ§œ νƒ€μ΄λ¨Έμ—μ„œ μ‚¬μš©ν•  ν˜„μž¬ μ‹œκ°μ„ μ„€μ •

    • jest.useRealTimers : μ œμŠ€νŠΈμ— μ‹€μ œ 타이머λ₯Ό μ‚¬μš©ν•˜λ„λ‘ μ§€μ‹œν•˜λŠ” 원상 볡귀 ν•¨μˆ˜

beforeEach, afterEach λ₯Ό μ‚¬μš©ν•˜μ—¬ 각 ν…ŒμŠ€νŠΈλ§ˆλ‹€ 사전 μ„€μ • μ½”λ“œλ₯Ό μ œκ±°ν•  수 μžˆλ‹€.

describe("greetByTime(", () => {
  beforeEach(() => {
    jest.useFakeTimers();
  })
  
  afterEach(() => {
    jest.useRealTimers();
  })
  
  test("μ•„μΉ¨μ—λŠ” 'good morning'을 λ°˜ν™˜ν•œλ‹€", () => {
    jest.setSystemTime(new Date(2023, 4, 23, 8, 0, 0));
    expect(greetByTime()).toBe("good morning")
  })
})

ν…ŒμŠ€νŠΈ μ„€μ •κ³Ό 파기

  • ν…ŒμŠ€νŠΈλ₯Ό μ‹€ν–‰ν•˜κΈ° μ „ κ³΅ν†΅μœΌλ‘œ μ„€μ •ν•΄μ•Ό ν•  μž‘μ—…μ΄ μžˆκ±°λ‚˜ ν…ŒμŠ€νŠΈ μ’…λ£Œ 후에 κ³΅ν†΅μœΌλ‘œ νŒŒκΈ°ν•˜κ³  싢은 μž‘μ—…μ΄ μžˆλŠ” 경우

  • μ„€μ • μž‘μ—…μ„ beforeAll , beforeEach λ₯Ό

  • 파기 μž‘μ—…μ„ afterAll, afterEach λ₯Ό μ‚¬μš©

beforeAll(() => console.log("1 - beforeAll"));
afterAll(() => console.log("1 - afterAll"));
beforeEach(() => console.log("1 - beforeEach"));
afterEach(() => console.log("1 - afterEach"));

test("", () => console.log("1 - test"));

describe("Scoped / Nested block", () => {
  beforeAll(() => console.log("2 - beforeAll"));
  afterAll(() => console.log("2 - afterAll"));
  beforeEach(() => console.log("2 - beforeEach"));
  afterEach(() => console.log("2 - afterEach")
  
  test("", () => console.log("2 - test"));
})

// 1 - beforeAll
// 1 - beforeEach
// 1 - test
// 1 - afterEach
// 2 - beforeAll
// 1 - beforeEach
// 2 - beforeEach
// 2 - test
// 2 - afterEach
// 1 - afterEach
// 2 - afterAll
// 1 - afterAll
Previousλ‹¨μœ„ ν…ŒμŠ€νŠΈ 검증NextUI μ»΄ν¬λ„ŒνŠΈ ν…ŒμŠ€νŠΈ

Last updated 10 months ago

제슀트의 APIλŠ” 의 μš©μ–΄ μ •μ˜λ₯Ό μΆ©μ‹€νžˆ λ”°λ₯΄μ§€ μ•ŠλŠ”λ‹€.

xUnit ν…ŒμŠ€νŠΈνŒ¨ν„΄