TL;DR

  • Colocation과 Separation 두 가지 테스트 배치 방식을 비교한다.
  • 파일 네이밍 규칙(.test/.spec)과 프레임워크 관례를 정리한다.
  • E2E 테스트는 별도 디렉토리로 분리하는 원칙을 제시한다.

1. 개념

테스트 파일의 위치와 규칙을 정해 탐색성과 일관성을 확보하는 전략이다.

2. 배경

배치와 명명 불일치로 테스트 검색 비용과 누락이 늘어났다.

3. 이유

테스트 커버리지와 팀 협업 효율을 높이기 위해 필요하다.

4. 특징

Colocation 원칙, tests 분리, 프레임워크별 권장 구조, E2E 분리가 핵심이다.

5. 상세 내용

프론트엔드 테스트 디렉토리 구조 - 최적의 테스트 파일 배치 전략

작성일: 2026-02-27 카테고리: Frontend / Testing / Project Structure 포함 내용: Colocation, tests, .test.ts, .spec.ts, Jest, Vitest, Playwright, Cypress, E2E, Unit Test, 모노레포, Kent C. Dodds


1. 왜 테스트 파일 배치가 중요한가?

1.1 테스트 파일 위치가 개발 생산성에 미치는 영향

┌─────────────────────────────────────────────────────────────────┐
│           테스트 파일 배치는 왜 중요한가?                        │
│                                                                   │
│  비유: 도서관의 책 정리 시스템                                   │
│                                                                   │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  잘 정리된 도서관:                                       │    │
│  │  ├── 요리책 → 요리 코너에 있다                           │    │
│  │  ├── 소설 → 문학 코너에 있다                             │    │
│  │  ├── 찾고 싶은 책을 바로 찾을 수 있다                    │    │
│  │  └── 새 책이 들어와도 어디 놓을지 명확하다               │    │
│  │                                                          │    │
│  │  정리 안 된 도서관:                                      │    │
│  │  ├── 요리책이 과학 코너에 섞여 있다                      │    │
│  │  ├── 같은 시리즈인데 1권과 2권이 다른 층에 있다          │    │
│  │  ├── 책을 찾느라 30분을 허비한다                         │    │
│  │  └── 결국 "그냥 안 읽지 뭐" → 독서 포기                 │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  테스트 파일도 마찬가지:                                         │
│  ├── 잘 배치하면 → 테스트를 쉽게 찾고, 쉽게 실행                │
│  ├── 못 배치하면 → 테스트를 못 찾고, 안 실행하게 됨             │
│  └── "테스트를 찾을 수 없으면 테스트를 실행하지 않는다"         │
│                                                                   │
│  Google 내부 연구 (2019):                                        │
│  ├── 테스트 파일이 소스 옆에 있을 때 → 테스트 커버리지 23% 높음 │
│  ├── 테스트 파일이 멀리 있을 때 → 새 기능에 테스트 누락 빈번    │
│  └── "눈에 보여야 마음에 있다" (Out of sight, out of mind)       │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

1.2 일관성의 중요성

┌─────────────────────────────────────────────────────────────────┐
│           일관성이 없으면 생기는 문제                            │
│                                                                   │
│  프로젝트 A의 현실:                                              │
│                                                                   │
│  src/                                                             │
│  ├── components/                                                  │
│  │   ├── Button/                                                  │
│  │   │   ├── Button.tsx                                           │
│  │   │   └── Button.test.tsx      ← 여기에 테스트가 있네?        │
│  │   ├── Modal/                                                   │
│  │   │   └── Modal.tsx            ← 테스트가 없네?               │
│  │   └── Header/                                                  │
│  │       └── Header.tsx           ← 이것도 없네?                 │
│  tests/                                                           │
│  ├── Modal.spec.ts                ← 여기 있었구나!               │
│  └── components/                                                  │
│      └── header-test.js           ← 이름도 다르고 확장자도 다름  │
│                                                                   │
│  팀원의 반응:                                                    │
│  ├── "Modal 테스트는 어디 있어요?" → 10분간 검색                │
│  ├── "Header 테스트 파일 이름이 왜 달라요?" → 혼란              │
│  ├── "저는 .test로 만들었는데 옆에는 .spec이네요" → 불일치      │
│  └── "그냥 새로 하나 만들까..." → 중복 테스트 발생              │
│                                                                   │
│  일관성의 원칙:                                                  │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  1. 테스트 파일 위치: 한 가지 방식만 사용                │    │
│  │  2. 파일 이름 규칙: .test.ts 또는 .spec.ts 하나만        │    │
│  │  3. 디렉토리 구조: 소스 구조를 그대로 반영                │    │
│  │  4. 문서화: README나 CONTRIBUTING에 규칙 명시             │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

2. 두 가지 주요 접근법

2.1 Colocation (테스트 파일을 소스 옆에 배치)

┌─────────────────────────────────────────────────────────────────┐
│           Colocation 전략 (소스 옆에 테스트 배치)               │
│                                                                   │
│  핵심 인물: Kent C. Dodds                                        │
│  원칙: "관련된 것은 가까이 두어라" (Colocation Principle)        │
│                                                                   │
│  Kent C. Dodds의 주장 (2019년 블로그):                           │
│  "파일을 가장 많이 사용하는 곳과 가까이 두면                     │
│   유지보수가 쉬워지고, 더 건강한 코드베이스가 된다."             │
│                                                                   │
│  디렉토리 구조 예시:                                             │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  src/                                                    │    │
│  │  ├── components/                                         │    │
│  │  │   ├── Button/                                         │    │
│  │  │   │   ├── Button.tsx          ← 소스 코드             │    │
│  │  │   │   ├── Button.test.tsx     ← 테스트 (바로 옆!)    │    │
│  │  │   │   ├── Button.stories.tsx  ← Storybook             │    │
│  │  │   │   └── Button.module.css   ← 스타일                │    │
│  │  │   ├── Modal/                                          │    │
│  │  │   │   ├── Modal.tsx                                   │    │
│  │  │   │   ├── Modal.test.tsx                              │    │
│  │  │   │   └── Modal.module.css                            │    │
│  │  │   └── Header/                                         │    │
│  │  │       ├── Header.tsx                                  │    │
│  │  │       └── Header.test.tsx                             │    │
│  │  ├── hooks/                                              │    │
│  │  │   ├── useAuth.ts                                      │    │
│  │  │   └── useAuth.test.ts                                 │    │
│  │  └── utils/                                              │    │
│  │      ├── formatDate.ts                                   │    │
│  │      └── formatDate.test.ts                              │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  장점:                                                           │
│  ├── 1. 관련 파일이 한눈에 보인다                                │
│  │      → Button.tsx 옆에 Button.test.tsx가 바로 있으니          │
│  │        "아, 이 컴포넌트에 테스트가 있구나" 즉시 확인          │
│  ├── 2. 파일 이동 시 테스트도 같이 이동                          │
│  │      → Button/ 폴더를 통째로 옮기면 테스트도 자동으로 따라감  │
│  │      → 별도 디렉토리면 동기화를 깜빡할 수 있음                │
│  ├── 3. 테스트 누락을 즉시 발견                                  │
│  │      → 폴더를 열었는데 .test.tsx가 없다? → "아, 작성해야겠다" │
│  ├── 4. import 경로가 짧다                                       │
│  │      → import { Button } from './Button'                      │
│  │      → (별도 디렉토리면 '../../../src/components/Button')      │
│  └── 5. 삭제할 때 깔끔하다                                       │
│         → 컴포넌트 폴더 삭제 = 테스트도 같이 삭제                │
│         → 고아 테스트(orphaned test) 방지                        │
│                                                                   │
│  단점:                                                           │
│  ├── 1. 폴더 안에 파일이 많아질 수 있다                          │
│  │      → Button.tsx, Button.test.tsx, Button.stories.tsx,        │
│  │        Button.module.css, index.ts → 5개 이상                 │
│  ├── 2. 소스와 테스트가 섞여서 빌드 설정이 필요                  │
│  │      → tsconfig에서 테스트 파일 제외 설정 필요                │
│  └── 3. 파일 탐색기에서 시각적으로 복잡해질 수 있음              │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

2.2 Separation (별도 test 디렉토리)

┌─────────────────────────────────────────────────────────────────┐
│           Separation 전략 (별도 __tests__ 디렉토리)             │
│                                                                   │
│  __tests__ 디렉토리는 Jest의 기본 설정에서 유래                  │
│  Jest는 기본적으로 __tests__/ 안의 파일을 테스트로 인식          │
│                                                                   │
│  디렉토리 구조 예시:                                             │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  src/                                                    │    │
│  │  ├── components/                                         │    │
│  │  │   ├── __tests__/                                      │    │
│  │  │   │   ├── Button.test.tsx                             │    │
│  │  │   │   ├── Modal.test.tsx                              │    │
│  │  │   │   └── Header.test.tsx                             │    │
│  │  │   ├── Button/                                         │    │
│  │  │   │   ├── Button.tsx                                  │    │
│  │  │   │   └── Button.module.css                           │    │
│  │  │   ├── Modal/                                          │    │
│  │  │   │   └── Modal.tsx                                   │    │
│  │  │   └── Header/                                         │    │
│  │  │       └── Header.tsx                                  │    │
│  │  ├── hooks/                                              │    │
│  │  │   ├── __tests__/                                      │    │
│  │  │   │   └── useAuth.test.ts                             │    │
│  │  │   └── useAuth.ts                                      │    │
│  │  └── utils/                                              │    │
│  │      ├── __tests__/                                      │    │
│  │      │   └── formatDate.test.ts                          │    │
│  │      └── formatDate.ts                                   │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  장점:                                                           │
│  ├── 1. 소스와 테스트가 명확히 분리                              │
│  │      → 소스 코드만 볼 때 테스트 파일이 시야를 방해하지 않음   │
│  ├── 2. 배포 시 테스트 파일을 쉽게 제외                          │
│  │      → __tests__/ 디렉토리만 .dockerignore에 추가하면 끝      │
│  ├── 3. Jest 기본 설정과 호환                                    │
│  │      → 별도 설정 없이 Jest가 자동으로 인식                    │
│  └── 4. 테스트 파일만 모아서 볼 수 있다                          │
│         → 코드 리뷰 시 테스트만 별도로 확인 가능                 │
│                                                                   │
│  단점:                                                           │
│  ├── 1. 소스와 테스트가 멀어진다                                 │
│  │      → Button.tsx를 수정하고 테스트를 깜빡할 확률 증가        │
│  ├── 2. 소스 디렉토리 구조와 동기화가 필요                       │
│  │      → components/ 이름 변경 시 __tests__/도 바꿔야 함        │
│  ├── 3. import 경로가 길어진다                                   │
│  │      → import { Button } from '../Button/Button'              │
│  └── 4. 파일 이동 시 테스트가 뒤에 남을 수 있다                  │
│         → 고아 테스트(orphaned test) 발생 위험                   │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

2.3 두 접근법의 비교 요약

┌─────────────────────────────────────────────────────────────────┐
│           Colocation vs Separation 비교표                       │
│                                                                   │
│  ┌─────────────┬──────────────────┬──────────────────┐          │
│  │ 기준         │ Colocation        │ Separation        │          │
│  ├─────────────┼──────────────────┼──────────────────┤          │
│  │ 테스트 발견  │ 매우 쉬움         │ 약간 어려움        │          │
│  │ 파일 이동    │ 자동으로 따라감   │ 수동 동기화 필요   │          │
│  │ import 경로  │ 짧다 ('./Button') │ 길다 ('../src/..') │          │
│  │ 폴더 정리    │ 파일 많아질 수    │ 깔끔하게 분리      │          │
│  │ 누락 방지    │ 즉시 발견 가능    │ 놓치기 쉬움        │          │
│  │ 빌드 제외    │ 설정 필요         │ 쉬움               │          │
│  │ 팀 선호도    │ 현대 프로젝트     │ 전통적/레거시       │          │
│  │ 대표 지지자  │ Kent C. Dodds     │ Jest 공식 문서      │          │
│  └─────────────┴──────────────────┴──────────────────┘          │
│                                                                   │
│  현재 업계 트렌드 (2025~2026):                                   │
│  ├── Colocation이 대세로 자리잡는 추세                           │
│  ├── React, Vue, Angular 공식 문서 모두 Colocation 예시 사용     │
│  ├── Vitest, Jest 모두 Colocation 지원                           │
│  └── Kent C. Dodds의 영향으로 프론트엔드 커뮤니티에서 표준화     │
│                                                                   │
│  결론: "특별한 이유가 없다면 Colocation을 선택하라"              │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

3. 파일 명명 규칙

3.1 .test.ts vs .spec.ts - 기원과 차이

┌─────────────────────────────────────────────────────────────────┐
│           .test.ts vs .spec.ts - 어디서 왔는가?                 │
│                                                                   │
│  .spec.ts의 기원:                                                │
│  ├── "spec" = "specification" (명세서)                           │
│  ├── BDD (Behavior-Driven Development)에서 유래                  │
│  ├── "소프트웨어의 동작 명세를 작성한다"는 의미                  │
│  ├── Jasmine (2010) → Mocha → Cypress에서 전통적으로 사용       │
│  └── RSpec (Ruby)에서 프론트엔드로 전파된 관례                   │
│                                                                   │
│  .test.ts의 기원:                                                │
│  ├── "test" = "테스트" (직관적)                                  │
│  ├── TDD (Test-Driven Development)에서 자연스럽게 사용           │
│  ├── Jest (2014, Facebook)가 기본 패턴으로 채택                  │
│  ├── Vitest (2022)도 Jest와 동일한 패턴 사용                     │
│  └── 더 직관적이고 이해하기 쉬움                                 │
│                                                                   │
│  프레임워크별 기본 설정:                                         │
│  ┌──────────────────┬────────────────────────┐                  │
│  │ 프레임워크         │ 기본 패턴               │                  │
│  ├──────────────────┼────────────────────────┤                  │
│  │ Jest              │ *.test.{ts,tsx,js,jsx}  │                  │
│  │ Vitest            │ *.test.{ts,tsx,js,jsx}  │                  │
│  │ Cypress           │ *.cy.{ts,tsx,js,jsx}    │ ← (v10부터)     │
│  │ Playwright        │ *.spec.{ts,js}          │                  │
│  │ Jasmine           │ *.spec.{ts,js}          │                  │
│  │ Angular CLI       │ *.spec.ts               │                  │
│  │ Vue CLI           │ *.spec.{ts,js}          │                  │
│  └──────────────────┴────────────────────────┘                  │
│                                                                   │
│  기술적으로 차이는 없다:                                         │
│  → 둘 다 단순한 파일 이름 규칙(naming convention)일 뿐           │
│  → 테스트 러너가 인식하는 패턴만 다를 뿐                        │
│  → 둘 중 어떤 것을 쓰든 테스트 기능은 동일                      │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

3.2 혼용하는 프로젝트의 규칙

┌─────────────────────────────────────────────────────────────────┐
│           .test와 .spec을 함께 쓰는 전략                        │
│                                                                   │
│  일부 프로젝트에서는 의도적으로 구분해서 사용:                   │
│                                                                   │
│  전략 1: 테스트 유형으로 구분                                    │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  .test.ts = Unit Test (단위 테스트)                      │    │
│  │  ├── Button.test.tsx    → Button 컴포넌트 유닛 테스트    │    │
│  │  ├── useAuth.test.ts    → useAuth 훅 유닛 테스트         │    │
│  │  └── formatDate.test.ts → formatDate 유틸 유닛 테스트    │    │
│  │                                                          │    │
│  │  .spec.ts = Integration Test (통합 테스트)               │    │
│  │  ├── LoginFlow.spec.tsx → 로그인 전체 흐름 통합 테스트   │    │
│  │  ├── CartCheckout.spec.tsx → 장바구니 결제 통합 테스트   │    │
│  │  └── UserProfile.spec.tsx → 프로필 CRUD 통합 테스트      │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  전략 2: 실행 환경으로 구분                                      │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  .test.ts = jsdom 환경 (Jest/Vitest)                     │    │
│  │  → 빠른 단위/통합 테스트                                 │    │
│  │                                                          │    │
│  │  .spec.ts = 브라우저 환경 (Playwright/Cypress)           │    │
│  │  → 실제 브라우저에서 실행되는 E2E 테스트                 │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  권장사항:                                                       │
│  ├── 팀 내에서 하나의 규칙을 정하고 ESLint로 강제하라            │
│  ├── eslint-plugin-filenames 또는 eslint-plugin-check-file 사용  │
│  └── 규칙 예시: "유닛은 .test, E2E는 .spec"을 CONTRIBUTING.md에  │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

4. 프레임워크별 권장 구조

4.1 React 프로젝트 (CRA / Vite)

┌─────────────────────────────────────────────────────────────────┐
│           React 프로젝트 - 권장 디렉토리 구조                   │
│                                                                   │
│  Colocation 방식 (가장 널리 사용됨):                             │
│                                                                   │
│  src/                                                             │
│  ├── components/                                                  │
│  │   ├── Button/                                                  │
│  │   │   ├── index.ts              ← 배럴 파일 (re-export)       │
│  │   │   ├── Button.tsx            ← 컴포넌트 구현               │
│  │   │   ├── Button.test.tsx       ← 유닛 테스트                 │
│  │   │   ├── Button.stories.tsx    ← Storybook 스토리            │
│  │   │   ├── Button.module.css     ← CSS Modules 스타일          │
│  │   │   └── Button.types.ts       ← 타입 정의 (선택)           │
│  │   ├── Modal/                                                   │
│  │   │   ├── index.ts                                             │
│  │   │   ├── Modal.tsx                                            │
│  │   │   ├── Modal.test.tsx                                       │
│  │   │   └── Modal.module.css                                     │
│  │   └── Form/                                                    │
│  │       ├── index.ts                                             │
│  │       ├── Form.tsx                                             │
│  │       ├── Form.test.tsx                                        │
│  │       ├── FormField.tsx         ← 하위 컴포넌트               │
│  │       └── FormField.test.tsx                                   │
│  ├── hooks/                                                       │
│  │   ├── useAuth.ts                                               │
│  │   ├── useAuth.test.ts                                          │
│  │   ├── useLocalStorage.ts                                       │
│  │   └── useLocalStorage.test.ts                                  │
│  ├── utils/                                                       │
│  │   ├── formatDate.ts                                            │
│  │   ├── formatDate.test.ts                                       │
│  │   ├── validators.ts                                            │
│  │   └── validators.test.ts                                       │
│  └── pages/                                                       │
│      ├── Home/                                                    │
│      │   ├── Home.tsx                                             │
│      │   └── Home.test.tsx                                        │
│      └── Dashboard/                                               │
│          ├── Dashboard.tsx                                         │
│          └── Dashboard.test.tsx                                    │
│                                                                   │
│  React Testing Library + Jest/Vitest 조합이 표준                 │
│  Kent C. Dodds가 만든 @testing-library/react가 사실상 표준       │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

4.2 Vue 프로젝트

┌─────────────────────────────────────────────────────────────────┐
│           Vue 프로젝트 - 권장 디렉토리 구조                     │
│                                                                   │
│  Vue CLI / Vite + Vue 3:                                         │
│                                                                   │
│  src/                                                             │
│  ├── components/                                                  │
│  │   ├── Button/                                                  │
│  │   │   ├── Button.vue            ← SFC (Single File Component) │
│  │   │   ├── Button.spec.ts        ← Vue는 .spec 전통이 강함    │
│  │   │   └── Button.stories.ts     ← Storybook                  │
│  │   ├── Modal/                                                   │
│  │   │   ├── Modal.vue                                            │
│  │   │   └── Modal.spec.ts                                        │
│  │   └── Form/                                                    │
│  │       ├── Form.vue                                             │
│  │       ├── Form.spec.ts                                         │
│  │       ├── FormField.vue                                        │
│  │       └── FormField.spec.ts                                    │
│  ├── composables/                  ← Vue 3의 Composition API     │
│  │   ├── useAuth.ts                                               │
│  │   ├── useAuth.spec.ts                                          │
│  │   ├── useCounter.ts                                            │
│  │   └── useCounter.spec.ts                                       │
│  ├── stores/                       ← Pinia 스토어                │
│  │   ├── auth.ts                                                  │
│  │   ├── auth.spec.ts                                             │
│  │   ├── cart.ts                                                  │
│  │   └── cart.spec.ts                                             │
│  └── views/                        ← Vue Router 페이지           │
│      ├── HomeView.vue                                             │
│      ├── HomeView.spec.ts                                         │
│      └── DashboardView.vue                                        │
│                                                                   │
│  Vue의 특징:                                                     │
│  ├── Vue CLI가 .spec.ts를 기본으로 생성해서 .spec 전통이 있음    │
│  ├── @vue/test-utils + Vitest 조합이 공식 권장 (2024~)           │
│  ├── Vitest가 Vue 팀과 같은 Evan You 생태계라서 호환성 우수      │
│  └── @testing-library/vue도 인기 (React에서 영향 받음)           │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

4.3 Next.js 프로젝트

┌─────────────────────────────────────────────────────────────────┐
│           Next.js 프로젝트 - 권장 디렉토리 구조                 │
│                                                                   │
│  Next.js는 특별한 주의가 필요하다!                               │
│                                                                   │
│  이유: App Router에서 특수 파일명 규칙이 있기 때문               │
│  ├── page.tsx    → 라우트 페이지                                 │
│  ├── layout.tsx  → 레이아웃                                      │
│  ├── loading.tsx → 로딩 UI                                       │
│  ├── error.tsx   → 에러 UI                                       │
│  └── route.ts    → API Route                                     │
│                                                                   │
│  문제: app/ 디렉토리 안에 .test.tsx를 두면?                      │
│  → Next.js가 이를 라우트로 인식하지는 않지만                     │
│  → 혼란을 줄 수 있고, 빌드 시 불필요한 파일이 포함될 수 있음    │
│                                                                   │
│  Next.js 공식 권장: __tests__ 디렉토리 사용                      │
│                                                                   │
│  방법 1: 프로젝트 루트에 __tests__ (Next.js 공식 문서 권장)      │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  my-app/                                                 │    │
│  │  ├── app/                                                │    │
│  │  │   ├── page.tsx                                        │    │
│  │  │   ├── layout.tsx                                      │    │
│  │  │   ├── dashboard/                                      │    │
│  │  │   │   └── page.tsx                                    │    │
│  │  │   └── api/                                            │    │
│  │  │       └── users/                                      │    │
│  │  │           └── route.ts                                │    │
│  │  ├── __tests__/                  ← 루트 레벨에 분리      │    │
│  │  │   ├── page.test.tsx                                   │    │
│  │  │   ├── dashboard/                                      │    │
│  │  │   │   └── page.test.tsx                               │    │
│  │  │   └── api/                                            │    │
│  │  │       └── users.test.ts                               │    │
│  │  ├── components/                 ← 공유 컴포넌트         │    │
│  │  │   ├── Button/                                         │    │
│  │  │   │   ├── Button.tsx                                  │    │
│  │  │   │   └── Button.test.tsx     ← 컴포넌트는 colocation│    │
│  │  │   └── Header/                                         │    │
│  │  │       ├── Header.tsx                                  │    │
│  │  │       └── Header.test.tsx                             │    │
│  │  └── jest.config.ts                                      │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  방법 2: app 내부에 __tests__ 폴더 사용                          │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  app/                                                    │    │
│  │  ├── __tests__/                                          │    │
│  │  │   └── page.test.tsx                                   │    │
│  │  ├── page.tsx                                            │    │
│  │  ├── dashboard/                                          │    │
│  │  │   ├── __tests__/                                      │    │
│  │  │   │   └── page.test.tsx                               │    │
│  │  │   └── page.tsx                                        │    │
│  │  └── layout.tsx                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  핵심 포인트:                                                    │
│  ├── App Router의 page/layout/route 파일은 colocation 어려움     │
│  ├── 공유 컴포넌트(components/)는 colocation이 여전히 유효       │
│  ├── Pages Router(pages/)는 colocation이 불가 (모두 라우트)      │
│  └── next.config.js에서 pageExtensions 설정으로 해결 가능하지만  │
│      공식 문서에서는 __tests__ 분리를 더 권장                    │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

4.4 Angular 프로젝트

┌─────────────────────────────────────────────────────────────────┐
│           Angular 프로젝트 - 기본 디렉토리 구조                 │
│                                                                   │
│  Angular CLI는 .spec.ts를 컴포넌트 옆에 자동 생성:              │
│                                                                   │
│  src/app/                                                         │
│  ├── components/                                                  │
│  │   ├── button/                                                  │
│  │   │   ├── button.component.ts        ← 컴포넌트 클래스       │
│  │   │   ├── button.component.html      ← 템플릿                │
│  │   │   ├── button.component.css       ← 스타일                │
│  │   │   └── button.component.spec.ts   ← CLI가 자동 생성!      │
│  │   └── modal/                                                   │
│  │       ├── modal.component.ts                                   │
│  │       ├── modal.component.html                                 │
│  │       ├── modal.component.css                                  │
│  │       └── modal.component.spec.ts                              │
│  ├── services/                                                    │
│  │   ├── auth.service.ts                                          │
│  │   └── auth.service.spec.ts           ← 서비스도 자동 생성    │
│  └── pipes/                                                       │
│      ├── format-date.pipe.ts                                      │
│      └── format-date.pipe.spec.ts       ← 파이프도 자동 생성    │
│                                                                   │
│  Angular의 특징:                                                 │
│  ├── CLI가 `ng generate component` 시 .spec.ts를 함께 생성       │
│  ├── Karma + Jasmine이 전통적 조합 (현재는 Jest 전환 추세)       │
│  ├── Colocation이 강제됨 (CLI 기본 동작)                         │
│  └── .spec.ts 사용이 Angular 생태계의 표준                       │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

5. E2E 테스트 디렉토리 구조

5.1 E2E 테스트는 항상 분리한다

┌─────────────────────────────────────────────────────────────────┐
│           E2E 테스트를 분리해야 하는 이유                       │
│                                                                   │
│  Unit/Integration 테스트 vs E2E 테스트:                          │
│                                                                   │
│  ┌──────────────────┬──────────────────┬─────────────────┐      │
│  │ 특성              │ Unit/Integration  │ E2E              │      │
│  ├──────────────────┼──────────────────┼─────────────────┤      │
│  │ 실행 환경         │ Node.js (jsdom)   │ 실제 브라우저    │      │
│  │ 속도              │ 밀리초~초          │ 초~분            │      │
│  │ 의존성            │ 소스 코드 직접     │ 배포된 앱        │      │
│  │ 테스트 대상       │ 함수, 컴포넌트    │ 전체 사용자 흐름 │      │
│  │ 실행 빈도         │ 매 커밋           │ CI/CD, 주기적   │      │
│  │ 설정 파일         │ jest/vitest.config│ playwright.config│      │
│  └──────────────────┴──────────────────┴─────────────────┘      │
│                                                                   │
│  분리 이유:                                                      │
│  ├── 1. 실행 환경이 완전히 다르다                                │
│  │      → Unit: Node.js에서 실행                                 │
│  │      → E2E: 실제 Chrome/Firefox/Safari에서 실행               │
│  ├── 2. 설정 파일이 다르다                                       │
│  │      → Unit: vitest.config.ts 또는 jest.config.ts             │
│  │      → E2E: playwright.config.ts 또는 cypress.config.ts       │
│  ├── 3. 실행 주기가 다르다                                       │
│  │      → Unit: 개발 중 수시로, 커밋 시 자동                     │
│  │      → E2E: PR 시, 배포 전, 야간 빌드                        │
│  ├── 4. 테스트 관점이 다르다                                     │
│  │      → Unit: "이 함수가 올바른 값을 반환하는가?"              │
│  │      → E2E: "사용자가 로그인할 수 있는가?"                    │
│  └── 5. 팀 역할이 다를 수 있다                                   │
│         → Unit: 개발자가 작성                                    │
│         → E2E: QA 엔지니어가 작성하기도 함                       │
│                                                                   │
│  권장 위치:                                                      │
│  ├── 프로젝트 루트의 e2e/ 디렉토리                               │
│  ├── 또는 tests/e2e/ 디렉토리                                    │
│  └── 절대로 src/ 안에 넣지 않는다                                │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

5.2 Playwright 기본 구조

┌─────────────────────────────────────────────────────────────────┐
│           Playwright E2E 테스트 디렉토리 구조                   │
│                                                                   │
│  Playwright: Microsoft가 만든 E2E 테스트 프레임워크              │
│  2024~2026년 현재 가장 인기 있는 E2E 도구                        │
│                                                                   │
│  기본 구조:                                                      │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  my-app/                                                 │    │
│  │  ├── src/                       ← 소스 코드              │    │
│  │  │   └── ...                                             │    │
│  │  ├── e2e/                       ← E2E 테스트 루트        │    │
│  │  │   ├── fixtures/              ← 테스트 데이터/설정     │    │
│  │  │   │   ├── auth.fixture.ts    ← 인증 fixture           │    │
│  │  │   │   └── test-data.json     ← 테스트 데이터          │    │
│  │  │   ├── pages/                 ← Page Object Model      │    │
│  │  │   │   ├── LoginPage.ts       ← 로그인 페이지 객체    │    │
│  │  │   │   ├── DashboardPage.ts   ← 대시보드 페이지 객체  │    │
│  │  │   │   └── BasePage.ts        ← 공통 페이지 객체      │    │
│  │  │   ├── specs/                 ← 실제 테스트 파일       │    │
│  │  │   │   ├── auth/                                       │    │
│  │  │   │   │   ├── login.spec.ts                           │    │
│  │  │   │   │   └── signup.spec.ts                          │    │
│  │  │   │   ├── dashboard/                                  │    │
│  │  │   │   │   └── widgets.spec.ts                         │    │
│  │  │   │   └── checkout/                                   │    │
│  │  │   │       └── payment.spec.ts                         │    │
│  │  │   └── helpers/               ← 테스트 헬퍼 함수      │    │
│  │  │       ├── api-helper.ts      ← API 호출 헬퍼         │    │
│  │  │       └── db-helper.ts       ← DB 시딩 헬퍼          │    │
│  │  └── playwright.config.ts       ← Playwright 설정       │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  Page Object Model (POM) 패턴:                                   │
│  ├── 페이지별 클래스를 만들어서 셀렉터와 액션을 캡슐화          │
│  ├── 테스트 코드에서 직접 셀렉터를 쓰지 않음                    │
│  ├── UI가 변경되면 Page Object만 수정 → 테스트는 그대로          │
│  └── Playwright 공식 문서에서 강력 권장                          │
│                                                                   │
│  예시:                                                           │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  // pages/LoginPage.ts                                   │    │
│  │  export class LoginPage {                                │    │
│  │    constructor(private page: Page) {}                     │    │
│  │                                                          │    │
│  │    async login(email: string, password: string) {        │    │
│  │      await this.page.fill('#email', email);              │    │
│  │      await this.page.fill('#password', password);        │    │
│  │      await this.page.click('[data-testid="login-btn"]'); │    │
│  │    }                                                     │    │
│  │  }                                                       │    │
│  │                                                          │    │
│  │  // specs/auth/login.spec.ts                             │    │
│  │  test('사용자가 로그인할 수 있다', async ({ page }) => { │    │
│  │    const loginPage = new LoginPage(page);                │    │
│  │    await loginPage.login('user@test.com', 'pass123');    │    │
│  │    await expect(page).toHaveURL('/dashboard');           │    │
│  │  });                                                     │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

5.3 Cypress 기본 구조

┌─────────────────────────────────────────────────────────────────┐
│           Cypress E2E 테스트 디렉토리 구조                      │
│                                                                   │
│  Cypress: 프론트엔드 친화적 E2E 테스트 프레임워크                │
│  2017년부터 인기, 현재도 많은 프로젝트에서 사용                  │
│                                                                   │
│  기본 구조 (Cypress v13+):                                       │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  my-app/                                                 │    │
│  │  ├── src/                       ← 소스 코드              │    │
│  │  │   └── ...                                             │    │
│  │  ├── cypress/                   ← Cypress 전용 디렉토리  │    │
│  │  │   ├── e2e/                   ← E2E 테스트 파일        │    │
│  │  │   │   ├── auth/                                       │    │
│  │  │   │   │   ├── login.cy.ts                             │    │
│  │  │   │   │   └── signup.cy.ts                            │    │
│  │  │   │   ├── dashboard/                                  │    │
│  │  │   │   │   └── widgets.cy.ts                           │    │
│  │  │   │   └── checkout/                                   │    │
│  │  │   │       └── payment.cy.ts                           │    │
│  │  │   ├── fixtures/              ← 테스트 데이터 (JSON)   │    │
│  │  │   │   ├── users.json                                  │    │
│  │  │   │   └── products.json                               │    │
│  │  │   ├── support/               ← 커스텀 커맨드/설정     │    │
│  │  │   │   ├── commands.ts        ← cy.login() 등          │    │
│  │  │   │   ├── e2e.ts             ← E2E 전역 설정          │    │
│  │  │   │   └── component.ts       ← 컴포넌트 테스트 설정  │    │
│  │  │   └── downloads/             ← 다운로드 파일 임시     │    │
│  │  └── cypress.config.ts          ← Cypress 설정 파일      │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  Cypress vs Playwright 구조 비교:                                │
│  ┌──────────────┬──────────────────┬──────────────────┐         │
│  │ 항목          │ Cypress           │ Playwright        │         │
│  ├──────────────┼──────────────────┼──────────────────┤         │
│  │ 테스트 위치   │ cypress/e2e/      │ e2e/specs/        │         │
│  │ 파일 확장자   │ .cy.ts            │ .spec.ts          │         │
│  │ 헬퍼          │ cypress/support/  │ e2e/helpers/      │         │
│  │ 데이터        │ cypress/fixtures/ │ e2e/fixtures/     │         │
│  │ 설정 파일     │ cypress.config.ts │ playwright.config │         │
│  │ POM 패턴      │ 선택적            │ 강력 권장          │         │
│  └──────────────┴──────────────────┴──────────────────┘         │
│                                                                   │
│  Cypress 고유 기능:                                              │
│  ├── Component Testing: 컴포넌트를 브라우저에서 직접 테스트      │
│  │   → cypress/support/component.ts에서 설정                     │
│  │   → src/ 안의 .cy.tsx 파일로 작성 (colocation 가능)           │
│  └── cy.intercept(): 네트워크 요청을 가로채서 모킹 가능          │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

6. 테스트 유형별 분리 전략

6.1 전체 테스트 유형과 배치 위치

┌─────────────────────────────────────────────────────────────────┐
│           테스트 유형별 파일 배치 전략                           │
│                                                                   │
│  비유: 병원의 검사 시스템                                        │
│  ├── 혈액 검사 (Unit Test): 간단하고 빠름, 많이 함              │
│  ├── X-ray 검사 (Integration Test): 여러 부위 확인, 중간        │
│  ├── 종합 건강검진 (E2E Test): 전체 검사, 느리고 비쌈           │
│  └── 외관 검사 (Visual Test): 겉보기가 정상인지 확인            │
│                                                                   │
│  ┌───────────────────────────────────────────────────────┐      │
│  │                                                        │      │
│  │    Unit Tests (유닛 테스트)                             │      │
│  │    ├── 위치: 소스 파일 옆 (Colocation)                  │      │
│  │    ├── 패턴: Button.test.tsx                            │      │
│  │    ├── 러너: Jest, Vitest                               │      │
│  │    └── 예시:                                            │      │
│  │        src/components/Button/                           │      │
│  │        ├── Button.tsx                                   │      │
│  │        └── Button.test.tsx   ← 바로 옆                 │      │
│  │                                                        │      │
│  ├───────────────────────────────────────────────────────┤      │
│  │                                                        │      │
│  │    Integration Tests (통합 테스트)                      │      │
│  │    ├── 위치: 소스 옆 또는 __tests__/integration/        │      │
│  │    ├── 패턴: LoginForm.integration.test.tsx             │      │
│  │    │         또는 __tests__/integration/login.test.tsx  │      │
│  │    ├── 러너: Jest, Vitest (+ MSW for API mocking)       │      │
│  │    └── 예시:                                            │      │
│  │        src/features/auth/                               │      │
│  │        ├── LoginForm.tsx                                │      │
│  │        ├── LoginForm.test.tsx              ← unit       │      │
│  │        └── LoginForm.integration.test.tsx  ← integration│      │
│  │                                                        │      │
│  ├───────────────────────────────────────────────────────┤      │
│  │                                                        │      │
│  │    E2E Tests (종단간 테스트)                            │      │
│  │    ├── 위치: 프로젝트 루트 e2e/ (항상 분리)             │      │
│  │    ├── 패턴: login.spec.ts                              │      │
│  │    ├── 러너: Playwright, Cypress                        │      │
│  │    └── 예시:                                            │      │
│  │        e2e/specs/auth/                                  │      │
│  │        └── login.spec.ts     ← 소스와 완전 분리        │      │
│  │                                                        │      │
│  ├───────────────────────────────────────────────────────┤      │
│  │                                                        │      │
│  │    Visual Tests (시각적 회귀 테스트)                    │      │
│  │    ├── 위치: Storybook stories 옆 (Colocation)          │      │
│  │    ├── 패턴: Button.stories.tsx (+ Chromatic)           │      │
│  │    ├── 도구: Storybook + Chromatic, Percy               │      │
│  │    └── 예시:                                            │      │
│  │        src/components/Button/                           │      │
│  │        ├── Button.tsx                                   │      │
│  │        ├── Button.test.tsx                              │      │
│  │        └── Button.stories.tsx ← visual test 역할       │      │
│  │                                                        │      │
│  └───────────────────────────────────────────────────────┘      │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

6.2 테스트 실행 명령어 분리

┌─────────────────────────────────────────────────────────────────┐
│           package.json scripts 분리 예시                        │
│                                                                   │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  {                                                       │    │
│  │    "scripts": {                                          │    │
│  │      "test": "vitest",                                   │    │
│  │      "test:unit": "vitest --dir src",                    │    │
│  │      "test:integration": "vitest --dir src               │    │
│  │                           --testPathPattern=integration", │    │
│  │      "test:e2e": "playwright test",                      │    │
│  │      "test:e2e:ui": "playwright test --ui",              │    │
│  │      "test:visual": "chromatic",                         │    │
│  │      "test:coverage": "vitest --coverage",               │    │
│  │      "test:ci": "vitest run && playwright test"          │    │
│  │    }                                                     │    │
│  │  }                                                       │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  CI/CD에서의 실행 순서:                                          │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  1. npm run test:unit        ← 가장 먼저 (빠름)         │    │
│  │  2. npm run test:integration ← 그 다음 (중간)           │    │
│  │  3. npm run test:e2e         ← 마지막 (느림)            │    │
│  │  4. npm run test:visual      ← PR에서만 (Chromatic)     │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  빠른 것부터 실행하는 이유:                                      │
│  → Unit이 실패하면 Integration/E2E를 실행할 필요 없음            │
│  → "빠른 피드백 루프"가 개발 생산성의 핵심                       │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

7. 모노레포에서의 테스트 구조

7.1 모노레포 기본 개념과 테스트 배치

┌─────────────────────────────────────────────────────────────────┐
│           모노레포(Monorepo)에서의 테스트 구조                  │
│                                                                   │
│  모노레포란?                                                     │
│  = 여러 패키지/앱을 하나의 저장소(repository)에서 관리           │
│  = Turborepo, Nx, pnpm workspace 등으로 구성                    │
│                                                                   │
│  비유: 한 건물에 여러 회사가 입주한 오피스 빌딩                  │
│  ├── 각 회사(패키지)는 독립적으로 운영                           │
│  ├── 공용 시설(공유 패키지)은 함께 사용                          │
│  └── 건물 전체 점검(E2E)은 빌딩 관리실에서 담당                  │
│                                                                   │
│  권장 구조:                                                      │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  monorepo-root/                                          │    │
│  │  ├── packages/                  ← 공유 패키지            │    │
│  │  │   ├── ui/                    ← UI 컴포넌트 라이브러리 │    │
│  │  │   │   ├── src/                                        │    │
│  │  │   │   │   ├── Button/                                 │    │
│  │  │   │   │   │   ├── Button.tsx                          │    │
│  │  │   │   │   │   └── Button.test.tsx  ← colocation      │    │
│  │  │   │   │   └── Modal/                                  │    │
│  │  │   │   │       ├── Modal.tsx                           │    │
│  │  │   │   │       └── Modal.test.tsx                      │    │
│  │  │   │   ├── vitest.config.ts   ← 패키지별 설정         │    │
│  │  │   │   └── package.json                                │    │
│  │  │   ├── utils/                 ← 공유 유틸리티          │    │
│  │  │   │   ├── src/                                        │    │
│  │  │   │   │   ├── formatDate.ts                           │    │
│  │  │   │   │   └── formatDate.test.ts                      │    │
│  │  │   │   ├── vitest.config.ts                            │    │
│  │  │   │   └── package.json                                │    │
│  │  │   └── test-utils/            ← 공유 테스트 유틸      │    │
│  │  │       ├── src/                                        │    │
│  │  │       │   ├── render.tsx      ← 커스텀 render         │    │
│  │  │       │   ├── mocks/          ← 공유 모킹             │    │
│  │  │       │   └── factories/      ← 데이터 팩토리         │    │
│  │  │       └── package.json                                │    │
│  │  ├── apps/                      ← 애플리케이션           │    │
│  │  │   ├── web/                   ← 웹 프론트엔드          │    │
│  │  │   │   ├── src/                                        │    │
│  │  │   │   │   └── ... (colocation 테스트)                 │    │
│  │  │   │   ├── e2e/               ← 앱별 E2E 테스트       │    │
│  │  │   │   │   ├── specs/                                  │    │
│  │  │   │   │   │   ├── login.spec.ts                       │    │
│  │  │   │   │   │   └── checkout.spec.ts                    │    │
│  │  │   │   │   └── playwright.config.ts                    │    │
│  │  │   │   ├── vitest.config.ts                            │    │
│  │  │   │   └── package.json                                │    │
│  │  │   └── admin/                 ← 관리자 앱              │    │
│  │  │       ├── src/                                        │    │
│  │  │       │   └── ...                                     │    │
│  │  │       ├── e2e/                                        │    │
│  │  │       └── package.json                                │    │
│  │  ├── turbo.json                 ← Turborepo 설정        │    │
│  │  ├── vitest.workspace.ts        ← Vitest 워크스페이스   │    │
│  │  └── package.json                                        │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

7.2 모노레포 테스트 실행 전략

┌─────────────────────────────────────────────────────────────────┐
│           모노레포에서 테스트 실행하기                           │
│                                                                   │
│  패키지별 독립 실행:                                             │
│  ├── cd packages/ui && npm test     → UI 패키지만 테스트        │
│  ├── cd apps/web && npm test        → 웹 앱만 테스트            │
│  └── cd apps/web && npm run test:e2e→ 웹 앱 E2E만 테스트        │
│                                                                   │
│  루트에서 전체 실행 (Turborepo):                                 │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  // turbo.json                                           │    │
│  │  {                                                       │    │
│  │    "pipeline": {                                         │    │
│  │      "test": {                                           │    │
│  │        "dependsOn": ["^build"],                          │    │
│  │        "outputs": ["coverage/**"]                        │    │
│  │      },                                                  │    │
│  │      "test:e2e": {                                       │    │
│  │        "dependsOn": ["build"],                           │    │
│  │        "outputs": []                                     │    │
│  │      }                                                   │    │
│  │    }                                                     │    │
│  │  }                                                       │    │
│  │                                                          │    │
│  │  // 실행                                                 │    │
│  │  turbo run test        → 모든 패키지 unit test 병렬 실행 │    │
│  │  turbo run test:e2e    → 모든 앱 E2E test 실행           │    │
│  │  turbo run test --filter=packages/ui → ui만 테스트       │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  핵심 원칙:                                                      │
│  ├── 1. 각 패키지는 자체 테스트 설정을 가진다                    │
│  ├── 2. 공유 테스트 유틸은 별도 패키지로 분리                    │
│  ├── 3. E2E는 앱(apps/) 레벨에서만 실행                          │
│  └── 4. CI에서는 변경된 패키지만 테스트 (turbo --filter)         │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

8. 테스트 유틸리티와 헬퍼 파일 배치

8.1 커스텀 render 함수 (test-utils.ts)

┌─────────────────────────────────────────────────────────────────┐
│           테스트 유틸리티 파일 배치                              │
│                                                                   │
│  test-utils.ts란?                                                │
│  = React Testing Library의 render를 감싸서                       │
│    Provider(테마, 라우터, 상태관리 등)를 자동으로 추가하는 함수  │
│  = 모든 테스트에서 import해서 사용                               │
│                                                                   │
│  위치:                                                           │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  src/                                                    │    │
│  │  ├── test-utils/                ← 테스트 유틸 전용       │    │
│  │  │   ├── index.ts               ← 배럴 파일             │    │
│  │  │   ├── render.tsx             ← 커스텀 render 함수    │    │
│  │  │   ├── setup.ts               ← 전역 설정             │    │
│  │  │   └── matchers.ts            ← 커스텀 matcher         │    │
│  │  └── components/                                         │    │
│  │      └── Button/                                         │    │
│  │          └── Button.test.tsx                              │    │
│  │              → import { render } from '@/test-utils'     │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  커스텀 render 함수 예시:                                        │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  // src/test-utils/render.tsx                            │    │
│  │  import { render, RenderOptions } from                   │    │
│  │    '@testing-library/react';                             │    │
│  │  import { ThemeProvider } from '@/providers/theme';      │    │
│  │  import { QueryClientProvider } from '@tanstack/..';     │    │
│  │                                                          │    │
│  │  function AllProviders({ children }) {                   │    │
│  │    return (                                              │    │
│  │      <QueryClientProvider client={queryClient}>          │    │
│  │        <ThemeProvider>                                    │    │
│  │          {children}                                      │    │
│  │        </ThemeProvider>                                   │    │
│  │      </QueryClientProvider>                              │    │
│  │    );                                                    │    │
│  │  }                                                       │    │
│  │                                                          │    │
│  │  export function customRender(                           │    │
│  │    ui: ReactElement,                                     │    │
│  │    options?: RenderOptions                               │    │
│  │  ) {                                                     │    │
│  │    return render(ui, {                                   │    │
│  │      wrapper: AllProviders, ...options                   │    │
│  │    });                                                   │    │
│  │  }                                                       │    │
│  │                                                          │    │
│  │  export * from '@testing-library/react';                 │    │
│  │  export { customRender as render };                      │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

8.2 모킹 (Mocks) 디렉토리

┌─────────────────────────────────────────────────────────────────┐
│           모킹 파일 배치 전략                                   │
│                                                                   │
│  모킹(Mocking)이란?                                              │
│  = 실제 API, DB, 외부 서비스를 가짜로 대체하는 것                │
│  = 테스트를 빠르고 안정적으로 만들기 위해 필수                   │
│                                                                   │
│  MSW (Mock Service Worker) 기반 구조:                            │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  src/                                                    │    │
│  │  ├── mocks/                     ← 모킹 전용 디렉토리    │    │
│  │  │   ├── handlers/              ← API 핸들러             │    │
│  │  │   │   ├── auth.ts            ← 인증 API 모킹          │    │
│  │  │   │   ├── users.ts           ← 사용자 API 모킹        │    │
│  │  │   │   ├── products.ts        ← 상품 API 모킹          │    │
│  │  │   │   └── index.ts           ← 모든 핸들러 합치기     │    │
│  │  │   ├── data/                  ← 모킹 데이터            │    │
│  │  │   │   ├── users.ts           ← 가짜 사용자 데이터     │    │
│  │  │   │   └── products.ts        ← 가짜 상품 데이터       │    │
│  │  │   ├── server.ts              ← MSW 서버 설정 (test)   │    │
│  │  │   └── browser.ts             ← MSW 브라우저 (dev)     │    │
│  │  └── ...                                                 │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  MSW의 장점:                                                     │
│  ├── 네트워크 레벨에서 가로채기 → fetch/axios 상관없이 동작      │
│  ├── 같은 핸들러를 개발(browser.ts)과 테스트(server.ts)에서 공유 │
│  ├── REST + GraphQL 모두 지원                                    │
│  └── Storybook에서도 사용 가능 (msw-storybook-addon)             │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

8.3 Fixtures와 Factories

┌─────────────────────────────────────────────────────────────────┐
│           Fixtures와 Factories 배치                             │
│                                                                   │
│  Fixture (고정값):                                               │
│  = 테스트에서 반복 사용하는 고정된 데이터                        │
│  = JSON 파일이나 상수로 정의                                     │
│                                                                   │
│  Factory (생성기):                                               │
│  = 테스트 데이터를 동적으로 생성하는 함수                        │
│  = 매번 다른 데이터가 필요할 때 유용                             │
│  = faker.js + fishery 같은 라이브러리 활용                       │
│                                                                   │
│  배치:                                                           │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  src/                                                    │    │
│  │  ├── test-utils/                                         │    │
│  │  │   ├── fixtures/              ← 고정 테스트 데이터     │    │
│  │  │   │   ├── user.fixture.ts                             │    │
│  │  │   │   │   → export const mockUser = {                 │    │
│  │  │   │   │       id: '1', name: 'John', ... }            │    │
│  │  │   │   ├── product.fixture.ts                          │    │
│  │  │   │   └── order.fixture.ts                            │    │
│  │  │   ├── factories/             ← 동적 데이터 생성기     │    │
│  │  │   │   ├── user.factory.ts                             │    │
│  │  │   │   │   → export const userFactory = Factory.define  │    │
│  │  │   │   │     <User>(({ sequence }) => ({               │    │
│  │  │   │   │       id: String(sequence),                   │    │
│  │  │   │   │       name: faker.person.fullName(),          │    │
│  │  │   │   │       email: faker.internet.email(),          │    │
│  │  │   │   │     }));                                      │    │
│  │  │   │   └── product.factory.ts                          │    │
│  │  │   └── index.ts                                        │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  Fixture vs Factory 선택 기준:                                   │
│  ┌──────────────┬────────────────────┬──────────────────┐       │
│  │ 상황          │ Fixture             │ Factory           │       │
│  ├──────────────┼────────────────────┼──────────────────┤       │
│  │ 항상 같은 값  │ 적합                │ 불필요            │       │
│  │ 매번 다른 값  │ 부적합              │ 적합              │       │
│  │ 관계형 데이터 │ 복잡                │ 적합              │       │
│  │ 대량 데이터   │ 불편                │ 적합              │       │
│  │ 스냅샷 비교   │ 적합                │ 비결정적 위험     │       │
│  └──────────────┴────────────────────┴──────────────────┘       │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

9. 안티패턴

9.1 소스와 동떨어진 거대한 tests 폴더

┌─────────────────────────────────────────────────────────────────┐
│           안티패턴 1: 거대한 __tests__ 폴더                     │
│                                                                   │
│  문제 상황:                                                      │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  src/                                                    │    │
│  │  ├── components/                                         │    │
│  │  │   ├── Button.tsx                                      │    │
│  │  │   ├── Modal.tsx                                       │    │
│  │  │   ├── Header.tsx                                      │    │
│  │  │   ├── Footer.tsx                                      │    │
│  │  │   ├── Sidebar.tsx                                     │    │
│  │  │   └── ... (50개 이상의 컴포넌트)                      │    │
│  │  __tests__/                     ← 모든 테스트가 여기!    │    │
│  │  ├── Button.test.tsx                                     │    │
│  │  ├── Modal.test.tsx                                      │    │
│  │  ├── Header.test.tsx                                     │    │
│  │  ├── auth.test.tsx                                       │    │
│  │  ├── utils.test.tsx                                      │    │
│  │  └── ... (수십 개의 테스트가 flat하게 나열)               │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  왜 나쁜가:                                                      │
│  ├── 소스와 테스트 사이의 거리가 멀다                            │
│  ├── 어떤 컴포넌트의 테스트인지 파악하기 어렵다                  │
│  ├── 파일이 많아지면 스크롤만 해도 시간이 걸린다                 │
│  ├── 소스 파일 삭제 시 테스트가 고아(orphan)로 남는다            │
│  └── 새 팀원이 "테스트 어디 있어요?" 질문이 반복된다             │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

9.2 테스트 파일명이 소스와 다른 이름

┌─────────────────────────────────────────────────────────────────┐
│           안티패턴 2: 소스와 다른 이름의 테스트 파일             │
│                                                                   │
│  문제 상황:                                                      │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  src/components/Button/Button.tsx                        │    │
│  │  __tests__/btn-test.js          ← 이름이 다르다!        │    │
│  │                                                          │    │
│  │  src/hooks/useAuth.ts                                    │    │
│  │  __tests__/authentication.spec.ts  ← 이름이 다르다!     │    │
│  │                                                          │    │
│  │  src/utils/formatDate.ts                                 │    │
│  │  __tests__/date-helpers-test.js    ← 이름도, 확장자도!  │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  왜 나쁜가:                                                      │
│  ├── "Button의 테스트는 어디?" → 검색해도 안 나옴               │
│  ├── grep "Button.test" → 결과 없음 (btn-test라서)              │
│  ├── 코드 리뷰 시 소스와 테스트 매칭이 안 됨                    │
│  └── 새 팀원이 테스트를 못 찾아서 중복으로 작성                  │
│                                                                   │
│  규칙: 소스 파일명 = 테스트 파일명                               │
│  ├── Button.tsx → Button.test.tsx                                │
│  ├── useAuth.ts → useAuth.test.ts                                │
│  └── formatDate.ts → formatDate.test.ts                          │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

9.3 E2E와 Unit 테스트를 같은 디렉토리에 혼합

┌─────────────────────────────────────────────────────────────────┐
│           안티패턴 3: E2E와 Unit 테스트 혼합                    │
│                                                                   │
│  문제 상황:                                                      │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  src/components/Button/                                  │    │
│  │  ├── Button.tsx                                          │    │
│  │  ├── Button.test.tsx        ← Jest로 실행 (unit)        │    │
│  │  └── Button.e2e.spec.ts     ← Playwright로 실행 (e2e)  │    │
│  │                                                          │    │
│  │  → npm test 실행 시 두 파일 다 잡히면?                   │    │
│  │  → E2E 테스트가 Unit 러너에서 실행되어 에러!             │    │
│  │  → 또는 느린 E2E가 빠른 Unit 사이에 섞여서 혼란!        │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  왜 나쁜가:                                                      │
│  ├── 실행 환경이 다른 테스트가 섞임 (jsdom vs 브라우저)          │
│  ├── 설정 파일 충돌 가능성                                       │
│  ├── CI에서 분리 실행이 어려움                                   │
│  └── 느린 E2E가 빠른 유닛 테스트 피드백을 지연시킴               │
│                                                                   │
│  해결: E2E는 반드시 별도 디렉토리에 배치                         │
│  ├── Unit/Integration → src/ 안에 (colocation)                   │
│  └── E2E → 프로젝트 루트 e2e/ 또는 tests/e2e/                   │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

9.4 테스트 유틸을 각 테스트 파일에 중복 작성

┌─────────────────────────────────────────────────────────────────┐
│           안티패턴 4: 테스트 유틸 중복 작성                     │
│                                                                   │
│  문제 상황:                                                      │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  // Button.test.tsx                                      │    │
│  │  function renderWithProviders(ui) {                      │    │
│  │    return render(                                        │    │
│  │      <ThemeProvider><QueryProvider>                      │    │
│  │        {ui}                                              │    │
│  │      </QueryProvider></ThemeProvider>                    │    │
│  │    );                                                    │    │
│  │  }                                                       │    │
│  │                                                          │    │
│  │  // Modal.test.tsx (같은 함수를 또 작성!)                │    │
│  │  function renderWithProviders(ui) {                      │    │
│  │    return render(                                        │    │
│  │      <ThemeProvider><QueryProvider>                      │    │
│  │        {ui}                                              │    │
│  │      </QueryProvider></ThemeProvider>                    │    │
│  │    );                                                    │    │
│  │  }                                                       │    │
│  │                                                          │    │
│  │  → 20개 파일에 같은 함수가 복사-붙여넣기 되어 있다면?    │    │
│  │  → Provider 변경 시 20곳을 다 수정해야 함!               │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  해결: 공통 test-utils로 추출                                    │
│  ├── src/test-utils/render.tsx에 한 번만 정의                    │
│  ├── 모든 테스트에서 import { render } from '@/test-utils'       │
│  └── Provider 변경 시 한 곳만 수정하면 끝                        │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

10. 설정 파일 가이드

10.1 Jest 설정

┌─────────────────────────────────────────────────────────────────┐
│           Jest 설정으로 테스트 파일 인식하기                     │
│                                                                   │
│  jest.config.ts:                                                 │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  export default {                                        │    │
│  │    // 테스트 파일 패턴 (어떤 파일을 테스트로 인식?)       │    │
│  │    testMatch: [                                          │    │
│  │      '<rootDir>/src/**/*.test.{ts,tsx}',                 │    │
│  │      '<rootDir>/src/**/__tests__/**/*.{ts,tsx}',         │    │
│  │    ],                                                    │    │
│  │                                                          │    │
│  │    // 테스트에서 제외할 패턴                              │    │
│  │    testPathIgnorePatterns: [                              │    │
│  │      '/node_modules/',                                   │    │
│  │      '/e2e/',           // E2E 테스트는 제외             │    │
│  │      '/dist/',                                           │    │
│  │    ],                                                    │    │
│  │                                                          │    │
│  │    // 모듈 경로 별칭 (import '@/test-utils' 지원)        │    │
│  │    moduleNameMapper: {                                   │    │
│  │      '^@/(.*)$': '<rootDir>/src/$1',                     │    │
│  │      '^@/test-utils$': '<rootDir>/src/test-utils',       │    │
│  │    },                                                    │    │
│  │                                                          │    │
│  │    // 전역 설정 파일                                      │    │
│  │    setupFilesAfterFramework: [                           │    │
│  │      '<rootDir>/src/test-utils/setup.ts',                │    │
│  │    ],                                                    │    │
│  │  };                                                      │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

10.2 Vitest 설정

┌─────────────────────────────────────────────────────────────────┐
│           Vitest 설정으로 테스트 파일 인식하기                   │
│                                                                   │
│  Vitest: Vite 기반의 차세대 테스트 러너                          │
│  Jest 호환 API + Vite의 빠른 빌드 = 빠른 테스트                 │
│                                                                   │
│  vitest.config.ts:                                               │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  import { defineConfig } from 'vitest/config';           │    │
│  │                                                          │    │
│  │  export default defineConfig({                           │    │
│  │    test: {                                               │    │
│  │      // 테스트 파일 포함 패턴                             │    │
│  │      include: [                                          │    │
│  │        'src/**/*.test.{ts,tsx}',                         │    │
│  │      ],                                                  │    │
│  │                                                          │    │
│  │      // 제외 패턴                                         │    │
│  │      exclude: [                                          │    │
│  │        'node_modules',                                   │    │
│  │        'e2e',                                            │    │
│  │        'dist',                                           │    │
│  │      ],                                                  │    │
│  │                                                          │    │
│  │      // 브라우저 환경 시뮬레이션                           │    │
│  │      environment: 'jsdom',                               │    │
│  │                                                          │    │
│  │      // 전역 설정                                         │    │
│  │      setupFiles: ['./src/test-utils/setup.ts'],          │    │
│  │                                                          │    │
│  │      // 커버리지 설정                                     │    │
│  │      coverage: {                                         │    │
│  │        provider: 'v8',                                   │    │
│  │        reporter: ['text', 'html', 'lcov'],               │    │
│  │        exclude: [                                        │    │
│  │          'src/test-utils/**',   // 테스트 유틸 제외      │    │
│  │          'src/mocks/**',        // 모킹 파일 제외        │    │
│  │          '**/*.stories.tsx',    // Storybook 제외        │    │
│  │        ],                                                │    │
│  │      },                                                  │    │
│  │    },                                                    │    │
│  │  });                                                     │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  Vitest의 장점 (Jest 대비):                                      │
│  ├── Vite 설정 재사용 → 별도 빌드 설정 불필요                    │
│  ├── ESM 네이티브 지원 → 변환 오류 적음                          │
│  ├── HMR 기반 watch 모드 → 변경된 테스트만 재실행 (빠름)         │
│  └── Jest 호환 API → 마이그레이션 쉬움                           │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

10.3 tsconfig에서 테스트 파일 제외

┌─────────────────────────────────────────────────────────────────┐
│           TypeScript 설정에서 테스트 파일 관리                   │
│                                                                   │
│  Colocation 방식을 사용할 때 빌드에서 테스트를 제외해야 한다:    │
│                                                                   │
│  tsconfig.json (전체 프로젝트):                                  │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  {                                                       │    │
│  │    "compilerOptions": { ... },                           │    │
│  │    "include": ["src"],                                   │    │
│  │    "exclude": [                                          │    │
│  │      "node_modules",                                     │    │
│  │      "**/*.test.ts",                                     │    │
│  │      "**/*.test.tsx",                                    │    │
│  │      "**/*.spec.ts",                                     │    │
│  │      "**/*.spec.tsx",                                    │    │
│  │      "src/test-utils",                                   │    │
│  │      "src/mocks",                                        │    │
│  │      "e2e"                                               │    │
│  │    ]                                                     │    │
│  │  }                                                       │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  tsconfig.test.json (테스트 전용):                               │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  {                                                       │    │
│  │    "extends": "./tsconfig.json",                         │    │
│  │    "compilerOptions": {                                  │    │
│  │      "types": ["vitest/globals",                         │    │
│  │                "@testing-library/jest-dom"]               │    │
│  │    },                                                    │    │
│  │    "include": [                                          │    │
│  │      "src/**/*.test.ts",                                 │    │
│  │      "src/**/*.test.tsx",                                │    │
│  │      "src/test-utils/**",                                │    │
│  │      "src/mocks/**"                                      │    │
│  │    ]                                                     │    │
│  │  }                                                       │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  이렇게 분리하면:                                                │
│  ├── 프로덕션 빌드에 테스트 코드가 포함되지 않음                 │
│  ├── IDE에서 테스트 파일의 타입 체크가 정상 동작                 │
│  └── vitest가 tsconfig.test.json을 자동으로 참조                 │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

11. 결론: 권장 디렉토리 구조 템플릿

11.1 종합 ASCII art 다이어그램

┌─────────────────────────────────────────────────────────────────┐
│           종합 권장 디렉토리 구조 (전체 템플릿)                 │
│                                                                   │
│  my-frontend-app/                                                │
│  │                                                               │
│  ├── src/                          ← 소스 코드 루트              │
│  │   ├── components/               ← 공통 UI 컴포넌트            │
│  │   │   ├── Button/                                             │
│  │   │   │   ├── index.ts          ← re-export                  │
│  │   │   │   ├── Button.tsx        ← 컴포넌트 구현               │
│  │   │   │   ├── Button.test.tsx   ← 유닛 테스트 (colocation)   │
│  │   │   │   ├── Button.stories.tsx← Storybook + visual test    │
│  │   │   │   └── Button.module.css ← 스타일                     │
│  │   │   ├── Modal/                                              │
│  │   │   │   ├── index.ts                                        │
│  │   │   │   ├── Modal.tsx                                       │
│  │   │   │   ├── Modal.test.tsx                                  │
│  │   │   │   └── Modal.stories.tsx                               │
│  │   │   └── Form/                                               │
│  │   │       ├── index.ts                                        │
│  │   │       ├── Form.tsx                                        │
│  │   │       ├── Form.test.tsx                                   │
│  │   │       ├── FormField.tsx                                   │
│  │   │       └── FormField.test.tsx                              │
│  │   │                                                           │
│  │   ├── features/                 ← 기능별 모듈                 │
│  │   │   ├── auth/                                               │
│  │   │   │   ├── components/                                     │
│  │   │   │   │   ├── LoginForm.tsx                               │
│  │   │   │   │   └── LoginForm.test.tsx                          │
│  │   │   │   ├── hooks/                                          │
│  │   │   │   │   ├── useAuth.ts                                  │
│  │   │   │   │   └── useAuth.test.ts                             │
│  │   │   │   └── api/                                            │
│  │   │   │       ├── authApi.ts                                  │
│  │   │   │       └── authApi.test.ts                             │
│  │   │   └── cart/                                               │
│  │   │       ├── components/                                     │
│  │   │       │   ├── CartItem.tsx                                │
│  │   │       │   └── CartItem.test.tsx                           │
│  │   │       └── hooks/                                          │
│  │   │           ├── useCart.ts                                   │
│  │   │           └── useCart.test.ts                              │
│  │   │                                                           │
│  │   ├── hooks/                    ← 공통 커스텀 훅              │
│  │   │   ├── useLocalStorage.ts                                  │
│  │   │   ├── useLocalStorage.test.ts                             │
│  │   │   ├── useDebounce.ts                                      │
│  │   │   └── useDebounce.test.ts                                 │
│  │   │                                                           │
│  │   ├── utils/                    ← 공통 유틸리티               │
│  │   │   ├── formatDate.ts                                       │
│  │   │   ├── formatDate.test.ts                                  │
│  │   │   ├── validators.ts                                       │
│  │   │   └── validators.test.ts                                  │
│  │   │                                                           │
│  │   ├── test-utils/               ← 테스트 공통 유틸           │
│  │   │   ├── index.ts              ← 배럴 파일                  │
│  │   │   ├── render.tsx            ← 커스텀 render              │
│  │   │   ├── setup.ts              ← 전역 테스트 설정           │
│  │   │   ├── fixtures/             ← 고정 테스트 데이터         │
│  │   │   │   ├── user.fixture.ts                                 │
│  │   │   │   └── product.fixture.ts                              │
│  │   │   └── factories/            ← 동적 데이터 생성기         │
│  │   │       ├── user.factory.ts                                 │
│  │   │       └── product.factory.ts                              │
│  │   │                                                           │
│  │   └── mocks/                    ← API 모킹 (MSW)             │
│  │       ├── handlers/                                           │
│  │       │   ├── auth.ts                                         │
│  │       │   ├── users.ts                                        │
│  │       │   └── index.ts                                        │
│  │       ├── data/                                               │
│  │       │   └── users.ts                                        │
│  │       ├── server.ts             ← 테스트용 MSW 서버          │
│  │       └── browser.ts            ← 개발용 MSW 브라우저        │
│  │                                                               │
│  ├── e2e/                          ← E2E 테스트 (완전 분리)     │
│  │   ├── fixtures/                 ← E2E 전용 fixture            │
│  │   │   └── auth.fixture.ts                                     │
│  │   ├── pages/                    ← Page Object Model           │
│  │   │   ├── BasePage.ts                                         │
│  │   │   ├── LoginPage.ts                                        │
│  │   │   └── DashboardPage.ts                                    │
│  │   ├── specs/                    ← E2E 테스트 파일             │
│  │   │   ├── auth/                                               │
│  │   │   │   ├── login.spec.ts                                   │
│  │   │   │   └── signup.spec.ts                                  │
│  │   │   └── checkout/                                           │
│  │   │       └── payment.spec.ts                                 │
│  │   └── helpers/                  ← E2E 헬퍼 함수              │
│  │       └── api-helper.ts                                       │
│  │                                                               │
│  ├── vitest.config.ts              ← Unit/Integration 설정      │
│  ├── playwright.config.ts          ← E2E 설정                   │
│  ├── tsconfig.json                 ← 프로덕션 TS 설정           │
│  ├── tsconfig.test.json            ← 테스트 전용 TS 설정        │
│  └── package.json                                                │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

11.2 프로젝트 규모별 권장사항

┌─────────────────────────────────────────────────────────────────┐
│           프로젝트 규모별 테스트 구조 권장사항                   │
│                                                                   │
│  ┌───────────────────────────────────────────────────────┐      │
│  │                                                        │      │
│  │  소규모 프로젝트 (1~3명, 컴포넌트 20개 미만)           │      │
│  │  ──────────────────────────────────────────            │      │
│  │  ├── Colocation만으로 충분                              │      │
│  │  ├── 별도 test-utils 불필요 (각 파일에서 직접 설정)     │      │
│  │  ├── E2E는 선택사항 (수동 테스트로도 가능)              │      │
│  │  ├── 모킹은 간단한 jest.mock()으로 충분                 │      │
│  │  └── 구조:                                              │      │
│  │      src/                                               │      │
│  │      ├── components/                                    │      │
│  │      │   ├── Button.tsx                                 │      │
│  │      │   └── Button.test.tsx                            │      │
│  │      └── utils/                                         │      │
│  │          ├── helpers.ts                                  │      │
│  │          └── helpers.test.ts                             │      │
│  │                                                        │      │
│  ├───────────────────────────────────────────────────────┤      │
│  │                                                        │      │
│  │  중규모 프로젝트 (3~10명, 컴포넌트 50~200개)           │      │
│  │  ──────────────────────────────────────────            │      │
│  │  ├── Colocation + test-utils 분리                       │      │
│  │  ├── MSW로 API 모킹 중앙화                              │      │
│  │  ├── E2E 테스트 (핵심 흐름만)                           │      │
│  │  ├── Storybook + Chromatic으로 visual regression        │      │
│  │  ├── CI/CD에 테스트 파이프라인 구축                      │      │
│  │  └── 구조:                                              │      │
│  │      src/                                               │      │
│  │      ├── components/ (colocation)                       │      │
│  │      ├── features/ (feature별 모듈)                     │      │
│  │      ├── test-utils/                                    │      │
│  │      └── mocks/                                         │      │
│  │      e2e/                                               │      │
│  │      └── specs/ (핵심 플로우)                            │      │
│  │                                                        │      │
│  ├───────────────────────────────────────────────────────┤      │
│  │                                                        │      │
│  │  대규모 프로젝트 (10명+, 모노레포)                     │      │
│  │  ──────────────────────────────────────────            │      │
│  │  ├── 모노레포 구조 (Turborepo/Nx)                       │      │
│  │  ├── 패키지별 독립 테스트 설정                           │      │
│  │  ├── 공유 test-utils 패키지 (packages/test-utils)       │      │
│  │  ├── 공유 MSW 핸들러 패키지                              │      │
│  │  ├── 앱별 E2E 테스트                                    │      │
│  │  ├── 변경된 패키지만 테스트 (turbo --filter)            │      │
│  │  ├── 병렬 테스트 실행으로 CI 시간 단축                   │      │
│  │  └── 구조:                                              │      │
│  │      packages/                                          │      │
│  │      ├── ui/src/ (colocation)                           │      │
│  │      ├── utils/src/ (colocation)                        │      │
│  │      └── test-utils/ (공유)                             │      │
│  │      apps/                                              │      │
│  │      ├── web/src/ + e2e/                                │      │
│  │      └── admin/src/ + e2e/                              │      │
│  │                                                        │      │
│  └───────────────────────────────────────────────────────┘      │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

11.3 최종 체크리스트

┌─────────────────────────────────────────────────────────────────┐
│           테스트 디렉토리 구조 최종 체크리스트                   │
│                                                                   │
│  프로젝트 시작 시 확인할 사항:                                   │
│                                                                   │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  [ ] 1. 테스트 배치 전략을 결정했는가?                   │    │
│  │        → Colocation (권장) 또는 __tests__ 중 하나 선택   │    │
│  │                                                          │    │
│  │  [ ] 2. 파일 이름 규칙을 정했는가?                       │    │
│  │        → .test.ts 또는 .spec.ts 중 하나 선택             │    │
│  │        → (선택) unit은 .test, e2e는 .spec 등 구분        │    │
│  │                                                          │    │
│  │  [ ] 3. E2E 테스트 디렉토리를 분리했는가?                │    │
│  │        → e2e/ 또는 tests/e2e/ 디렉토리 생성              │    │
│  │                                                          │    │
│  │  [ ] 4. 테스트 유틸리티 디렉토리를 만들었는가?           │    │
│  │        → test-utils/ (커스텀 render, setup 등)           │    │
│  │                                                          │    │
│  │  [ ] 5. 모킹 전략을 정했는가?                            │    │
│  │        → mocks/ 디렉토리 (MSW 핸들러 등)                 │    │
│  │                                                          │    │
│  │  [ ] 6. tsconfig에서 테스트 파일을 제외했는가?           │    │
│  │        → 프로덕션 빌드에 포함되지 않도록                  │    │
│  │                                                          │    │
│  │  [ ] 7. package.json scripts를 분리했는가?               │    │
│  │        → test:unit, test:e2e 등 구분                     │    │
│  │                                                          │    │
│  │  [ ] 8. CI/CD 파이프라인에 테스트를 추가했는가?          │    │
│  │        → unit → integration → e2e 순서로 실행            │    │
│  │                                                          │    │
│  │  [ ] 9. 팀 규칙을 문서화했는가?                          │    │
│  │        → CONTRIBUTING.md에 테스트 규칙 명시               │    │
│  │                                                          │    │
│  │  [ ] 10. ESLint로 규칙을 강제했는가?                     │    │
│  │         → 파일명 패턴, import 규칙 등 자동 검사           │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  한 줄 요약:                                                     │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  "유닛 테스트는 소스 옆에(Colocation),                   │    │
│  │   E2E 테스트는 루트에 분리(Separation),                  │    │
│  │   일관된 이름 규칙을 지키고, 문서화하라!"                │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

관련 키워드

Colocation, __tests__, .test.ts, .spec.ts, Jest, Vitest, Playwright, Cypress, E2E Test, Unit Test, Integration Test, Visual Test, Kent C. Dodds, React Testing Library, MSW, Mock Service Worker, Page Object Model, Storybook, Chromatic, Monorepo, Turborepo, Nx, test-utils, Fixture, Factory, tsconfig, CI/CD, BDD, TDD, Test Pyramid, Colocation Principle, Orphaned Test, Next.js App Router, Vue Test Utils, Angular CLI, fishery, faker.js