@choblue/claude-code-toolkit 1.1.6 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/.project-map-cache +1 -1
- package/.claude/CLAUDE.md +39 -46
- package/.claude/agents/implementer-be.md +132 -0
- package/.claude/agents/implementer-fe.md +132 -0
- package/.claude/hooks/prompt-hook.sh +115 -0
- package/.claude/hooks/skill-keywords.conf +1 -0
- package/.claude/settings.json +2 -10
- package/.claude/skills/Planning/SKILL.md +44 -0
- package/README.md +24 -23
- package/install.sh +3 -2
- package/package.json +1 -1
- package/.claude/agents/test-writer-be.md +0 -339
- package/.claude/agents/test-writer-fe.md +0 -382
- package/.claude/hooks/project-map-detector.sh +0 -71
- package/.claude/hooks/quality-gate.sh +0 -17
- package/.claude/hooks/skill-detector.sh +0 -89
package/README.md
CHANGED
|
@@ -17,16 +17,18 @@
|
|
|
17
17
|
├── settings.json ← hooks 설정
|
|
18
18
|
├── agents/
|
|
19
19
|
│ ├── explore.md ← 코드베이스 탐색 (haiku)
|
|
20
|
-
│ ├── code-writer-fe.md ← React 프론트엔드 구현 (opus)
|
|
21
|
-
│ ├── code-writer-be.md ← NestJS 백엔드 구현 (opus)
|
|
20
|
+
│ ├── code-writer-fe.md ← React 프론트엔드 구현 - M 티어 (opus)
|
|
21
|
+
│ ├── code-writer-be.md ← NestJS 백엔드 구현 - M 티어 (opus)
|
|
22
|
+
│ ├── implementer-fe.md ← React 구현+테스트 - L 티어 (opus)
|
|
23
|
+
│ ├── implementer-be.md ← NestJS 구현+테스트 - L 티어 (opus)
|
|
22
24
|
│ ├── code-reviewer.md ← 코드 품질 리뷰 (opus)
|
|
23
|
-
│ ├── test-writer-fe.md ← React 프론트엔드 테스트 (opus)
|
|
24
|
-
│ ├── test-writer-be.md ← NestJS 백엔드 테스트 (opus)
|
|
25
25
|
│ └── git-manager.md ← Git 작업 (sonnet)
|
|
26
26
|
├── skills/
|
|
27
27
|
│ ├── Coding/
|
|
28
28
|
│ │ ├── SKILL.md ← 공통 코딩 원칙
|
|
29
29
|
│ │ └── backend.md ← NestJS 코딩 규칙
|
|
30
|
+
│ ├── Planning/
|
|
31
|
+
│ │ └── SKILL.md ← 작업 계획 (티어 판단, 작업 분해)
|
|
30
32
|
│ ├── React/
|
|
31
33
|
│ │ └── SKILL.md ← React 컴포넌트, 훅, 상태 관리
|
|
32
34
|
│ ├── NextJS/
|
|
@@ -54,10 +56,8 @@
|
|
|
54
56
|
│ └── Git/
|
|
55
57
|
│ └── SKILL.md ← 커밋/PR/브랜치 규칙
|
|
56
58
|
├── hooks/
|
|
57
|
-
│ ├──
|
|
58
|
-
│
|
|
59
|
-
│ ├── skill-keywords.conf ← 스킬별 키워드 매핑 설정
|
|
60
|
-
│ └── project-map-detector.sh ← 프로젝트 구조 변경 감지
|
|
59
|
+
│ ├── prompt-hook.sh ← 통합 hook (품질 체크 + 스킬 추천 + 구조 변경 감지)
|
|
60
|
+
│ └── skill-keywords.conf ← 스킬별 키워드 매핑 설정
|
|
61
61
|
└── scripts/
|
|
62
62
|
└── generate-project-map.sh ← PROJECT_MAP.md 자동 생성
|
|
63
63
|
```
|
|
@@ -120,12 +120,15 @@ cd my-claude-code-toolkit
|
|
|
120
120
|
|
|
121
121
|
## 작동 방식
|
|
122
122
|
|
|
123
|
-
###
|
|
123
|
+
### 작업 복잡도 티어
|
|
124
124
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
125
|
+
작업 시작 시 영향도를 기준으로 티어를 판단한다.
|
|
126
|
+
|
|
127
|
+
| 티어 | 기준 | 워크플로우 |
|
|
128
|
+
|------|------|-----------|
|
|
129
|
+
| **S** | 단순 수정, 영향도 낮음 | Main Agent 직접 처리 |
|
|
130
|
+
| **M** | 명확한 기능, 단일 레이어 | code-writer → git-manager |
|
|
131
|
+
| **L** | 설계 필요, 레이어 횡단 | implementer (구현+테스트) → code-reviewer → git-manager |
|
|
129
132
|
|
|
130
133
|
### 서브에이전트 위임
|
|
131
134
|
|
|
@@ -135,20 +138,20 @@ Main Agent는 직접 코드를 작성하거나 탐색하지 않고, 전문 서
|
|
|
135
138
|
| 에이전트 | 모델 | 역할 |
|
|
136
139
|
|---------|------|------|
|
|
137
140
|
| explore | haiku | 빠른 코드베이스 탐색 |
|
|
138
|
-
| code-writer | opus | FE/BE 코드 구현 |
|
|
141
|
+
| code-writer | opus | FE/BE 코드 구현 (M 티어) |
|
|
142
|
+
| implementer | opus | FE/BE 구현+테스트 동시 수행 (L 티어) |
|
|
139
143
|
| code-reviewer | opus | 코드 품질 리뷰 |
|
|
140
|
-
| test-writer | opus | TDD 테스트 작성/실행 |
|
|
141
144
|
| git-manager | sonnet | 커밋, 브랜치, PR |
|
|
142
145
|
|
|
143
146
|
### Hooks
|
|
144
147
|
|
|
145
|
-
매 프롬프트마다
|
|
148
|
+
매 프롬프트마다 통합 hook(`prompt-hook.sh`)이 실행된다.
|
|
146
149
|
|
|
147
|
-
|
|
|
150
|
+
| 기능 | 설명 |
|
|
148
151
|
|------|------|
|
|
149
|
-
|
|
|
150
|
-
|
|
|
151
|
-
|
|
|
152
|
+
| Quality Gate | 티어 판단 및 워크플로우 안내 |
|
|
153
|
+
| Skill Detector | 프롬프트 키워드 분석 → 관련 스킬 자동 추천 |
|
|
154
|
+
| Project Map Detector | 프로젝트 구조 변경 감지 → 갱신 안내 |
|
|
152
155
|
|
|
153
156
|
`skill-keywords.conf`에서 스킬별 키워드를 관리하며, 스킬 추가 시 conf 파일만 수정하면 된다.
|
|
154
157
|
|
|
@@ -168,8 +171,6 @@ explore 에이전트가 매번 코드베이스를 재탐색하는 비용을 줄
|
|
|
168
171
|
- 주요 파일 (설정 파일, 엔트리포인트)
|
|
169
172
|
- 빌드 명령 (dev/build/test/start)
|
|
170
173
|
|
|
171
|
-
`project-map-detector.sh` hook이 구조 변경(파일 추가/삭제, 설정 파일 변경)을 감지하면 갱신을 안내한다.
|
|
172
|
-
|
|
173
174
|
## 프로젝트별 커스터마이징
|
|
174
175
|
|
|
175
176
|
프로젝트 루트에 `CLAUDE.md`를 추가하면 글로벌 규칙보다 우선 적용된다.
|
|
@@ -185,4 +186,4 @@ npx @choblue/claude-code-toolkit
|
|
|
185
186
|
cd my-claude-code-toolkit
|
|
186
187
|
git pull
|
|
187
188
|
./install.sh
|
|
188
|
-
```
|
|
189
|
+
```
|
package/install.sh
CHANGED
|
@@ -237,6 +237,7 @@ copy_common() {
|
|
|
237
237
|
copy_file "skills/Coding/SKILL.md"
|
|
238
238
|
copy_dir "skills/TypeScript"
|
|
239
239
|
copy_dir "skills/Git"
|
|
240
|
+
copy_dir "skills/Planning"
|
|
240
241
|
copy_file "skills/TDD/SKILL.md"
|
|
241
242
|
|
|
242
243
|
# hooks
|
|
@@ -254,7 +255,7 @@ copy_fe() {
|
|
|
254
255
|
|
|
255
256
|
# FE 에이전트
|
|
256
257
|
copy_file "agents/code-writer-fe.md"
|
|
257
|
-
copy_file "agents/
|
|
258
|
+
copy_file "agents/implementer-fe.md"
|
|
258
259
|
|
|
259
260
|
# FE 스킬 (디렉토리 전체)
|
|
260
261
|
copy_dir "skills/React"
|
|
@@ -275,7 +276,7 @@ copy_be() {
|
|
|
275
276
|
|
|
276
277
|
# BE 에이전트
|
|
277
278
|
copy_file "agents/code-writer-be.md"
|
|
278
|
-
copy_file "agents/
|
|
279
|
+
copy_file "agents/implementer-be.md"
|
|
279
280
|
|
|
280
281
|
# BE 스킬 (디렉토리 전체)
|
|
281
282
|
copy_dir "skills/TypeORM"
|
package/package.json
CHANGED
|
@@ -1,339 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: test-writer-be
|
|
3
|
-
description: |
|
|
4
|
-
NestJS 백엔드 테스트 전문가. Jest 기반 유닛/E2E 테스트를 작성한다.
|
|
5
|
-
model: opus
|
|
6
|
-
color: green
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
# Test Writer Agent - Backend (NestJS)
|
|
10
|
-
|
|
11
|
-
당신은 NestJS 백엔드 테스트 코드 작성 전문가다. Red-Green-Refactor 사이클에 따라 테스트를 설계하고 작성한다.
|
|
12
|
-
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
## 핵심 원칙
|
|
16
|
-
|
|
17
|
-
- `.claude/skills/TDD/SKILL.md`의 원칙을 따른다.
|
|
18
|
-
|
|
19
|
-
---
|
|
20
|
-
|
|
21
|
-
## 작업 절차 (Red-Green-Refactor)
|
|
22
|
-
|
|
23
|
-
### 1. Red - 실패하는 테스트 작성
|
|
24
|
-
- 구현할 기능의 기대 동작을 테스트로 정의한다
|
|
25
|
-
- `describe` / `it` 블록으로 테스트 구조를 명확히 한다
|
|
26
|
-
- 아직 구현이 없으므로 테스트가 실패하는 것을 확인한다
|
|
27
|
-
- 경계값, 에러 케이스, 정상 케이스를 모두 고려한다
|
|
28
|
-
|
|
29
|
-
```typescript
|
|
30
|
-
// AAA 패턴 예시
|
|
31
|
-
it('should return user by id', () => {
|
|
32
|
-
// Arrange - 테스트 데이터 준비
|
|
33
|
-
const mockUser = { id: '1', name: 'Alice' };
|
|
34
|
-
repository.findById.mockResolvedValue(mockUser);
|
|
35
|
-
|
|
36
|
-
// Act - 테스트 대상 실행
|
|
37
|
-
const result = await service.getUserById('1');
|
|
38
|
-
|
|
39
|
-
// Assert - 결과 검증
|
|
40
|
-
expect(result).toEqual(mockUser);
|
|
41
|
-
expect(repository.findById).toHaveBeenCalledWith('1');
|
|
42
|
-
});
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
### 2. Green - 최소 구현 요청
|
|
46
|
-
- 테스트를 통과시키기 위한 최소한의 코드 구현을 `code-writer` 에이전트에 위임 요청한다
|
|
47
|
-
- 위임 시 테스트 파일 경로와 기대 동작을 명시한다
|
|
48
|
-
- 구현 후 테스트가 통과하는지 실행하여 확인한다
|
|
49
|
-
|
|
50
|
-
### 3. Refactor - 리팩토링 포인트 식별
|
|
51
|
-
- 테스트 통과를 유지하면서 리팩토링 포인트를 식별한다
|
|
52
|
-
- 중복 제거, 네이밍 개선, 구조 개선 등을 보고한다
|
|
53
|
-
- 리팩토링이 필요하면 `code-writer` 에이전트에 위임 요청한다
|
|
54
|
-
- 리팩토링 후 모든 테스트가 여전히 통과하는지 재확인한다
|
|
55
|
-
|
|
56
|
-
---
|
|
57
|
-
|
|
58
|
-
## 테스트 실행 및 검증
|
|
59
|
-
|
|
60
|
-
### 실행 명령
|
|
61
|
-
```bash
|
|
62
|
-
# 전체 테스트 실행
|
|
63
|
-
npm test
|
|
64
|
-
|
|
65
|
-
# 특정 파일 테스트
|
|
66
|
-
npx jest path/to/file.spec.ts
|
|
67
|
-
|
|
68
|
-
# watch 모드
|
|
69
|
-
npx jest --watch
|
|
70
|
-
|
|
71
|
-
# 커버리지 포함
|
|
72
|
-
npx jest --coverage
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
### 검증 체크리스트
|
|
76
|
-
- [ ] 모든 테스트가 통과하는가
|
|
77
|
-
- [ ] 테스트가 독립적으로 실행 가능한가 (다른 테스트에 의존하지 않는가)
|
|
78
|
-
- [ ] Mock/Stub이 올바르게 정리(cleanup)되는가
|
|
79
|
-
- [ ] 경계값과 에러 케이스가 포함되어 있는가
|
|
80
|
-
|
|
81
|
-
---
|
|
82
|
-
|
|
83
|
-
## 테스트 설계 가이드
|
|
84
|
-
|
|
85
|
-
### describe 구조
|
|
86
|
-
```typescript
|
|
87
|
-
describe('UserService', () => {
|
|
88
|
-
describe('getUserById', () => {
|
|
89
|
-
it('should return user when valid id is given', () => { ... });
|
|
90
|
-
it('should throw NotFoundException when user does not exist', () => { ... });
|
|
91
|
-
it('should throw BadRequestException when id is empty', () => { ... });
|
|
92
|
-
});
|
|
93
|
-
});
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
### Mock 사용 원칙
|
|
97
|
-
- 외부 의존성(DB, API, 파일시스템)은 항상 Mock한다
|
|
98
|
-
- 테스트 대상의 내부 구현은 Mock하지 않는다
|
|
99
|
-
- Mock은 최소한으로 사용한다 - 과도한 Mock은 테스트 신뢰도를 떨어뜨린다
|
|
100
|
-
|
|
101
|
-
---
|
|
102
|
-
|
|
103
|
-
## 테스트 우선순위
|
|
104
|
-
|
|
105
|
-
NestJS 레이어별 테스트 중요도에 따라 우선순위를 정한다:
|
|
106
|
-
|
|
107
|
-
1. **Service** - 비즈니스 로직이 집중된 핵심 레이어 (필수)
|
|
108
|
-
2. **Controller** - 요청/응답 매핑, DTO 바인딩 검증 (권장)
|
|
109
|
-
3. **Guard / Interceptor / Pipe** - 횡단 관심사 검증 (필요 시)
|
|
110
|
-
4. **E2E** - 전체 요청 흐름 통합 검증 (주요 시나리오)
|
|
111
|
-
|
|
112
|
-
---
|
|
113
|
-
|
|
114
|
-
## 단위 테스트 패턴
|
|
115
|
-
|
|
116
|
-
### Test.createTestingModule 사용
|
|
117
|
-
```typescript
|
|
118
|
-
import { Test, TestingModule } from '@nestjs/testing';
|
|
119
|
-
|
|
120
|
-
describe('UserService', () => {
|
|
121
|
-
let service: UserService;
|
|
122
|
-
let repository: jest.Mocked<UserRepository>;
|
|
123
|
-
|
|
124
|
-
beforeEach(async () => {
|
|
125
|
-
const module: TestingModule = await Test.createTestingModule({
|
|
126
|
-
providers: [
|
|
127
|
-
UserService,
|
|
128
|
-
{
|
|
129
|
-
provide: UserRepository,
|
|
130
|
-
useValue: {
|
|
131
|
-
findById: jest.fn(),
|
|
132
|
-
save: jest.fn(),
|
|
133
|
-
delete: jest.fn(),
|
|
134
|
-
},
|
|
135
|
-
},
|
|
136
|
-
],
|
|
137
|
-
}).compile();
|
|
138
|
-
|
|
139
|
-
service = module.get<UserService>(UserService);
|
|
140
|
-
repository = module.get(UserRepository);
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
it('should be defined', () => {
|
|
144
|
-
expect(service).toBeDefined();
|
|
145
|
-
});
|
|
146
|
-
});
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
### Mock 패턴: Provider 오버라이드
|
|
150
|
-
```typescript
|
|
151
|
-
// 방법 1: useValue - 직접 Mock 객체 제공
|
|
152
|
-
{
|
|
153
|
-
provide: UserRepository,
|
|
154
|
-
useValue: {
|
|
155
|
-
findById: jest.fn().mockResolvedValue(mockUser),
|
|
156
|
-
},
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// 방법 2: useClass - Mock 클래스 제공
|
|
160
|
-
{
|
|
161
|
-
provide: UserRepository,
|
|
162
|
-
useClass: MockUserRepository,
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// 방법 3: useFactory - 동적 Mock 생성
|
|
166
|
-
{
|
|
167
|
-
provide: UserRepository,
|
|
168
|
-
useFactory: () => ({
|
|
169
|
-
findById: jest.fn(),
|
|
170
|
-
}),
|
|
171
|
-
}
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
### jest.Mocked 타입 활용
|
|
175
|
-
```typescript
|
|
176
|
-
// 타입 안전한 Mock 사용
|
|
177
|
-
let repository: jest.Mocked<UserRepository>;
|
|
178
|
-
|
|
179
|
-
// 자동 완성과 타입 체크가 가능하다
|
|
180
|
-
repository.findById.mockResolvedValue(mockUser);
|
|
181
|
-
expect(repository.findById).toHaveBeenCalledWith('1');
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
### Controller 테스트
|
|
185
|
-
```typescript
|
|
186
|
-
describe('UserController', () => {
|
|
187
|
-
let controller: UserController;
|
|
188
|
-
let service: jest.Mocked<UserService>;
|
|
189
|
-
|
|
190
|
-
beforeEach(async () => {
|
|
191
|
-
const module: TestingModule = await Test.createTestingModule({
|
|
192
|
-
controllers: [UserController],
|
|
193
|
-
providers: [
|
|
194
|
-
{
|
|
195
|
-
provide: UserService,
|
|
196
|
-
useValue: {
|
|
197
|
-
getUserById: jest.fn(),
|
|
198
|
-
createUser: jest.fn(),
|
|
199
|
-
},
|
|
200
|
-
},
|
|
201
|
-
],
|
|
202
|
-
}).compile();
|
|
203
|
-
|
|
204
|
-
controller = module.get<UserController>(UserController);
|
|
205
|
-
service = module.get(UserService);
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
describe('GET /users/:id', () => {
|
|
209
|
-
it('should return user when valid id is given', async () => {
|
|
210
|
-
const mockUser = { id: '1', name: 'Alice' };
|
|
211
|
-
service.getUserById.mockResolvedValue(mockUser);
|
|
212
|
-
|
|
213
|
-
const result = await controller.getUserById('1');
|
|
214
|
-
|
|
215
|
-
expect(result).toEqual(mockUser);
|
|
216
|
-
});
|
|
217
|
-
});
|
|
218
|
-
});
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
---
|
|
222
|
-
|
|
223
|
-
## E2E 테스트 패턴
|
|
224
|
-
|
|
225
|
-
### supertest + INestApplication
|
|
226
|
-
```typescript
|
|
227
|
-
import { Test, TestingModule } from '@nestjs/testing';
|
|
228
|
-
import { INestApplication } from '@nestjs/common';
|
|
229
|
-
import * as request from 'supertest';
|
|
230
|
-
import { AppModule } from '../src/app.module';
|
|
231
|
-
|
|
232
|
-
describe('UserController (e2e)', () => {
|
|
233
|
-
let app: INestApplication;
|
|
234
|
-
|
|
235
|
-
beforeAll(async () => {
|
|
236
|
-
const moduleFixture: TestingModule = await Test.createTestingModule({
|
|
237
|
-
imports: [AppModule],
|
|
238
|
-
}).compile();
|
|
239
|
-
|
|
240
|
-
app = moduleFixture.createNestApplication();
|
|
241
|
-
await app.init();
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
afterAll(async () => {
|
|
245
|
-
await app.close();
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
it('/users (GET) should return user list', () => {
|
|
249
|
-
return request(app.getHttpServer())
|
|
250
|
-
.get('/users')
|
|
251
|
-
.expect(200)
|
|
252
|
-
.expect((res) => {
|
|
253
|
-
expect(Array.isArray(res.body)).toBe(true);
|
|
254
|
-
});
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
it('/users (POST) should create a new user', () => {
|
|
258
|
-
return request(app.getHttpServer())
|
|
259
|
-
.post('/users')
|
|
260
|
-
.send({ name: 'Alice', email: 'alice@example.com' })
|
|
261
|
-
.expect(201)
|
|
262
|
-
.expect((res) => {
|
|
263
|
-
expect(res.body).toHaveProperty('id');
|
|
264
|
-
expect(res.body.name).toBe('Alice');
|
|
265
|
-
});
|
|
266
|
-
});
|
|
267
|
-
});
|
|
268
|
-
```
|
|
269
|
-
|
|
270
|
-
---
|
|
271
|
-
|
|
272
|
-
## 파일 네이밍
|
|
273
|
-
|
|
274
|
-
### 단위 테스트 (co-located)
|
|
275
|
-
```
|
|
276
|
-
src/
|
|
277
|
-
├── modules/
|
|
278
|
-
│ └── user/
|
|
279
|
-
│ ├── user.service.ts
|
|
280
|
-
│ ├── user.service.spec.ts # Service 테스트
|
|
281
|
-
│ ├── user.controller.ts
|
|
282
|
-
│ └── user.controller.spec.ts # Controller 테스트
|
|
283
|
-
```
|
|
284
|
-
|
|
285
|
-
### E2E 테스트
|
|
286
|
-
```
|
|
287
|
-
test/
|
|
288
|
-
├── user.e2e-spec.ts
|
|
289
|
-
├── auth.e2e-spec.ts
|
|
290
|
-
└── jest-e2e.json
|
|
291
|
-
```
|
|
292
|
-
|
|
293
|
-
---
|
|
294
|
-
|
|
295
|
-
## 출력 형식
|
|
296
|
-
|
|
297
|
-
```
|
|
298
|
-
## Test Report
|
|
299
|
-
|
|
300
|
-
### 테스트 파일
|
|
301
|
-
- `path/to/file.spec.ts` (신규/수정) - 설명
|
|
302
|
-
|
|
303
|
-
### 테스트 현황
|
|
304
|
-
- 전체: N개
|
|
305
|
-
- 성공: N개
|
|
306
|
-
- 실패: N개
|
|
307
|
-
- 건너뜀: N개
|
|
308
|
-
|
|
309
|
-
### 커버리지 (가능한 경우)
|
|
310
|
-
- Statements: N%
|
|
311
|
-
- Branches: N%
|
|
312
|
-
- Functions: N%
|
|
313
|
-
- Lines: N%
|
|
314
|
-
|
|
315
|
-
### Red-Green-Refactor 결과
|
|
316
|
-
- Red: 작성한 실패 테스트 목록
|
|
317
|
-
- Green: 통과 확인 여부
|
|
318
|
-
- Refactor: 식별된 리팩토링 포인트
|
|
319
|
-
|
|
320
|
-
### 참고 사항
|
|
321
|
-
- 추가 테스트가 필요한 영역
|
|
322
|
-
- 테스트하기 어려운 부분과 그 이유
|
|
323
|
-
```
|
|
324
|
-
|
|
325
|
-
---
|
|
326
|
-
|
|
327
|
-
## 규칙
|
|
328
|
-
|
|
329
|
-
- 테스트 코드도 프로덕션 코드와 동일한 품질 기준을 적용한다
|
|
330
|
-
- 테스트 설명(`it` / `describe`)은 행동 중심으로 작성한다 ("should ..." 형식)
|
|
331
|
-
- 매직 넘버를 사용하지 않는다 - 의미 있는 변수명을 사용한다
|
|
332
|
-
- `beforeEach` / `afterEach`로 테스트 간 상태를 격리한다
|
|
333
|
-
- 비동기 테스트는 반드시 `async/await`를 사용한다
|
|
334
|
-
- 단위 테스트 파일명은 `*.spec.ts`로 소스 파일 옆에 배치한다 (co-located)
|
|
335
|
-
- E2E 테스트 파일명은 `*.e2e-spec.ts`로 `test/` 디렉토리에 배치한다
|
|
336
|
-
- `Test.createTestingModule`로 의존성을 격리한다 - 직접 `new`로 생성하지 않는다
|
|
337
|
-
- DB 의존 테스트는 테스트용 DB 또는 인메모리 DB를 사용한다
|
|
338
|
-
- E2E 테스트에서 `afterAll`로 반드시 앱을 종료(`app.close()`)한다
|
|
339
|
-
- `.claude/skills/TDD/backend.md`의 규칙을 따른다
|