test-driven-developmentlisted
Install: claude install-skill HarryJhin/groundwork
# test-driven-development
테스트를 먼저 쓴다. 실패를 확인한다. 통과시킬 최소 코드를 쓴다.
**핵심 원칙**: 테스트가 실패하는 것을 보지 않았다면 그 테스트가 옳은 것을 검사하는지 모른다.
**규칙을 글자 그대로 지키지 않는 것은 규칙의 취지를 저버리는 것이다.**
## 적용 대상
**항상**: 새 기능, 버그 수정, 리팩터링, 동작 변경.
**예외(사용자에게 묻는다)**: 버리는 프로토타입, 코드 생성기가 출력한 코드(스키마·클라이언트 스텁 등), 설정 파일. 네가 직접 쓰는 코드는 예외가 아니다.
"이번만 TDD를 건너뛰자"는 생각이 들면 멈춘다. 그것이 합리화다.
**경로 기준**: 이 문서의 셸 블록에 나오는 테스트 파일 경로는 대상 프로젝트의 repo 루트 기준이고, 커맨드는 그 루트에서 돈다.
**테스트 러너**: 아래 블록은 Node와 jest를 예시로 쓴다. 대상 프로젝트의 테스트 커맨드로 바꿔 실행한다.
**출력**: 이 스킬이 남기는 것은 테스트와 그것을 통과시키는 구현이다. 완료를 주장하기 전에 `groundwork:verification-before-completion`으로 넘긴다.
## 철칙
```
실패하는 테스트 없이 프로덕션 코드를 쓰지 않는다
```
테스트보다 코드를 먼저 썼다면 지운다. 처음부터 다시 한다.
예외는 없다. 먼저 쓴 그 코드를 이렇게 다룬다.
- "참고용"으로 남기지 않는다
- 그 코드에 맞춰 테스트를 짜 맞추지 않는다
- 쳐다보지 않는다
- 지운다는 것은 지운다는 뜻이다
테스트만 보고 구현을 처음부터 다시 쓴다.
## RED-GREEN-REFACTOR
### RED. 실패하는 테스트를 쓴다
무엇이 일어나야 하는지 보여주는 최소 테스트 하나를 쓴다.
좋은 예:
```typescript
test('retries failed operations 3 times', async () => {
let attempts = 0;
const operation = () => {
attempts++;
if (attempts < 3) throw new Error('fail');
return 'success';
};
const result = await retryOperation(operation);
expect(result).toBe('success');
expect(attempts).toBe(3);
});
```
이름이 명확하고, 실제 동작을 검사하고, 한 가지만 본다.
나쁜 예:
```typescript
test('retry works', async () => {
const mock = jest.fn()
.mockRejectedValueOnce(new Error())
.mockRejectedValueOnce(new Error())
.mockResolvedValueOnce('success');
await retryOperation(mock);
expect(mock).toHa