작업 계획서를 기반으로 TDD 방식으로 구현합니다. "구현 시작", "코드 작성", "개발 진행", "TDD" 등의 요청 시 활성화됩니다.
Executes TDD cycles from task plans: writes failing tests, implements minimal code, refactors while maintaining tests. Activates on "implement", "code", "TDD" requests.
/plugin marketplace add dlddu/claude-plugin-marketplace/plugin install agile-tdd-workflow@dlddu-pluginsThis skill inherits all available tools. When active, it can use any tool Claude has access to.
이 스킬은 작업 계획서를 기반으로 테스트 주도 개발(TDD) 방식으로 구현을 진행합니다. 테스트와 구현은 항상 동시에 진행되며, 테스트 실패 시 명세와 비교하여 논리적 오류 여부를 판단합니다.
docs/tasks/TASK-{번호}-*.md 작업 계획서가 존재해야 합니다. ┌─────────────────────────────────────────┐
│ │
▼ │
┌───────┐ ┌───────┐ ┌───────────┐ │
│ RED │────▶│ GREEN │────▶│ REFACTOR │────┘
└───────┘ └───────┘ └───────────┘
테스트 최소한의 코드 개선
작성/실패 구현/통과 (테스트 유지)
진행할 작업 계획서를 확인합니다:
## 확인 사항
- [ ] 구현할 인수 테스트 ID
- [ ] 관련 명세 및 요구사항
- [ ] 예상 파일 구조
- [ ] 추적 어노테이션 ID
중요: 구현 코드를 작성하기 전에 반드시 테스트를 먼저 작성합니다.
// tests/acceptance/feature.test.js
// @trace US-001-AT-1
describe('US-001-AT-1: {인수 테스트 제목}', () => {
// @trace US-001-AT-1
it('Given {전제조건}, When {행동}, Then {결과}', async () => {
// Given: 전제조건 설정
const initialState = setupInitialState();
// When: 사용자 행동 수행
const result = await performAction(initialState);
// Then: 결과 검증
expect(result).toMatchExpectedOutcome();
});
});
// tests/unit/module.test.js
// @trace US-001-AT-1
// @spec SPEC-001-FR-1
describe('{모듈명}', () => {
// @trace US-001-AT-1
describe('{함수명}', () => {
it('{동작 설명}', () => {
// Arrange
const input = prepareInput();
// Act
const result = functionUnderTest(input);
// Assert
expect(result).toBe(expectedValue);
});
});
});
# 테스트 실행
npm test
# 예상 결과: 테스트 실패 (RED)
# ✗ Given {전제조건}, When {행동}, Then {결과}
# Error: {함수/모듈}이 정의되지 않음
테스트를 통과시키기 위한 최소한의 코드를 작성합니다.
// src/feature.js
// @trace US-001-AT-1
// @spec SPEC-001-FR-1
/**
* {기능 설명}
* @trace US-001-AT-1
* @spec SPEC-001-FR-1
*/
function featureImplementation(input) {
// 테스트를 통과시키는 최소한의 구현
return expectedOutput;
}
module.exports = { featureImplementation };
모든 구현 코드에는 다음 어노테이션을 포함합니다:
| 어노테이션 | 용도 | 예시 |
|---|---|---|
@trace | 인수 테스트 연결 | @trace US-001-AT-1 |
@spec | 명세 요구사항 연결 | @spec SPEC-001-FR-1 |
# 테스트 실행
npm test
# 예상 결과: 테스트 통과 (GREEN)
# ✓ Given {전제조건}, When {행동}, Then {결과}
테스트가 실패할 경우, 다음 순서로 원인을 분석합니다:
## 테스트 실패 분석
### 실패한 테스트
- ID: US-001-AT-1
- 예상: {예상 결과}
- 실제: {실제 결과}
### 명세 확인
- 관련 명세: SPEC-001-FR-1
- 명세 내용: {명세에 정의된 동작}
### 판단
□ 명세와 테스트가 일치하는가?
├─ 예 → 구현 수정 필요
└─ 아니오 → 논리적 오류 확인
| 상황 | 판단 | 조치 |
|---|---|---|
| 테스트가 명세와 불일치 | 테스트 오류 | 테스트 수정 |
| 테스트가 명세와 일치 | 구현 오류 | 구현 수정 |
| 명세 자체에 모순 | 명세 오류 | 명세 검토 요청 |
테스트 실패
│
▼
명세 비교 ──▶ 논리적 오류? ──▶ 예 ──▶ 명세/테스트 검토
│ │
│ ▼ 아니오
│ │
▼ ▼
구현 수정 ◀──────────┘
│
▼
테스트 실행
│
├─▶ 실패 ──▶ (반복)
│
▼
통과 ──▶ 다음 단계
테스트가 통과한 후, 코드 품질을 개선합니다:
## 리팩토링 체크리스트
- [ ] 중복 코드 제거
- [ ] 명확한 변수/함수 이름
- [ ] 단일 책임 원칙 준수
- [ ] 적절한 에러 처리
- [ ] 추적 어노테이션 유지
중요: 리팩토링 후에도 모든 테스트가 통과해야 합니다.
# 리팩토링 후 테스트
npm test
# 모든 테스트 통과 확인
# ✓ 모든 테스트 통과
docs/traceability-matrix.md를 업데이트합니다:
## 역방향 추적 (구현 → 요구사항)
| 코드/테스트 파일 | 추적 ID | 관련 인수 테스트 | 관련 명세 |
|-----------------|---------|-----------------|-----------|
| src/feature.js:10 | @trace US-001-AT-1 | US-001-AT-1 | SPEC-001-FR-1 |
| tests/acceptance/feature.test.js:5 | @trace US-001-AT-1 | US-001-AT-1 | - |
| tests/unit/module.test.js:8 | @trace US-001-AT-1 | US-001-AT-1 | SPEC-001-FR-1 |
# 커밋 전 로컬 테스트
npm test
npm run lint
npm run build
# 커밋 및 푸시
git add .
git commit -m "feat: US-001-AT-1 구현
- @trace US-001-AT-1
- @spec SPEC-001-FR-1"
git push
CI 파이프라인이 통과할 때까지 반복합니다.
# TASK-001: {작업 제목}
## 메타데이터
- **상태**: 완료
- **완료일**: YYYY-MM-DD
## 완료 조건
- [x] 인수 테스트 코드 작성
- [x] 단위 테스트 코드 작성
- [x] 구현 코드 작성
- [x] 모든 테스트 통과
- [x] CI 파이프라인 통과
- [x] 추적성 매트릭스 업데이트
docs/tasks/PROGRESS.md를 업데이트합니다.
작업 계획서: TASK-001, 관련 AT: US-001-AT-1
// tests/acceptance/auth.test.js
// @trace US-001-AT-1
describe('US-001-AT-1: 사용자 로그인', () => {
// @trace US-001-AT-1
it('Given 등록된 사용자, When 올바른 자격증명 입력, Then 로그인 성공', async () => {
// Given
const user = { email: 'test@example.com', password: 'password123' };
await createUser(user);
// When
const result = await login(user.email, user.password);
// Then
expect(result.success).toBe(true);
expect(result.token).toBeDefined();
});
});
// src/auth.js
// @trace US-001-AT-1
// @spec SPEC-001-FR-1
/**
* 사용자 로그인
* @trace US-001-AT-1
* @spec SPEC-001-FR-1
*/
async function login(email, password) {
const user = await findUserByEmail(email);
if (!user || !verifyPassword(password, user.passwordHash)) {
return { success: false, error: '인증 실패' };
}
const token = generateToken(user);
return { success: true, token };
}
module.exports = { login };
// src/auth.js (리팩토링 후)
// @trace US-001-AT-1
// @spec SPEC-001-FR-1
const { AuthenticationError } = require('./errors');
/**
* 사용자 로그인 처리
* @trace US-001-AT-1
* @spec SPEC-001-FR-1
* @param {string} email - 사용자 이메일
* @param {string} password - 비밀번호
* @returns {Promise<{success: boolean, token?: string}>}
*/
async function login(email, password) {
const user = await findUserByEmail(email);
if (!user) {
throw new AuthenticationError('사용자를 찾을 수 없습니다');
}
const isValidPassword = await verifyPassword(password, user.passwordHash);
if (!isValidPassword) {
throw new AuthenticationError('비밀번호가 일치하지 않습니다');
}
const token = await generateToken(user);
return { success: true, token };
}
module.exports = { login };
구현 완료 후:
task-planning 스킬을 사용하여 다음 작업을 확인합니다.