| name | tdd |
| description | 레드-그린-리팩터 루프를 사용하는 테스트 주도 개발. 사용자가 TDD로 기능을 만들거나 버그를 수정하고 싶거나, "레드-그린-리팩터"를 언급하거나, 통합 테스트를 원하거나, 테스트 우선 개발을 요청할 때 사용. |
Test-Driven Development
철학
핵심 원칙: 테스트는 구현 세부사항이 아니라 공개 인터페이스를 통해 동작(behavior)을 검증해야 함. 코드는 완전히 바뀔 수 있어도 테스트는 그렇지 않아야 함.
좋은 테스트는 통합 스타일: 공개 API를 통해 실제 코드 경로를 실행. 시스템이 무엇을 하는지 기술하지, 어떻게 하는지 기술하지 않음. 좋은 테스트는 명세처럼 읽힘 — "사용자가 유효한 장바구니로 결제할 수 있다"는 어떤 능력이 있는지 정확히 알려줌. 이런 테스트는 내부 구조에 신경 쓰지 않으므로 리팩토링에서 살아남음.
나쁜 테스트는 구현에 결합됨. 내부 협력자를 mock하거나, private 메소드를 테스트하거나, 외부 수단(인터페이스 사용 대신 DB 직접 쿼리 등)으로 검증. 경고 신호: 리팩토링했는데 동작은 안 바뀌었는데 테스트가 깨지면. 내부 함수 이름을 바꿨는데 테스트가 실패한다면, 그 테스트는 동작이 아니라 구현을 테스트하고 있었던 것.
예시는 tests.md, mocking 가이드는 mocking.md 참고.
안티패턴: 가로 슬라이스(Horizontal Slices)
모든 테스트를 먼저 다 쓰고, 그 다음 모든 구현을 쓰지 마. 이게 "가로 슬라이싱" — RED를 "모든 테스트 작성"으로, GREEN을 "모든 코드 작성"으로 다루는 것.
이렇게 하면 쓰레기 테스트가 나옴:
- 일괄로 작성된 테스트는 실제 동작이 아니라 상상된 동작을 테스트
- 사용자 직면 동작이 아니라 모양 (데이터 구조, 함수 시그니처)을 테스트하게 됨
- 테스트가 실제 변경에 둔감해짐 — 동작이 깨졌는데 통과하고, 동작이 멀쩡한데 실패함
- 헤드라이트보다 빨리 가게 됨, 구현을 이해하기 전에 테스트 구조에 커밋
올바른 접근: 트레이서 불릿을 통한 세로 슬라이스. 테스트 1개 → 구현 1개 → 반복. 각 테스트는 이전 사이클에서 배운 것에 응답. 방금 코드를 썼기 때문에, 어떤 동작이 중요하고 어떻게 검증할지 정확히 앎.
잘못 (가로):
RED: test1, test2, test3, test4, test5
GREEN: impl1, impl2, impl3, impl4, impl5
올바름 (세로):
RED→GREEN: test1→impl1
RED→GREEN: test2→impl2
RED→GREEN: test3→impl3
...
워크플로우
1. 계획
코드베이스를 탐색할 때, 테스트 이름과 인터페이스 어휘가 프로젝트 언어와 일치하도록 도메인 용어집을 사용하고, 건드리는 영역의 ADR을 존중.
코드를 쓰기 전에:
물어봐: "공개 인터페이스가 어떻게 생겨야 해? 어떤 동작이 테스트하기에 가장 중요해?"
모든 것을 테스트할 수 없어. 어떤 동작이 가장 중요한지 사용자와 정확히 확인. 가능한 모든 엣지 케이스가 아니라, 핵심 경로와 복잡한 로직에 테스트 노력을 집중.
2. 트레이서 불릿(Tracer Bullet)
시스템에 대한 한 가지를 확인하는 테스트 1개를 작성:
RED: 첫 번째 동작에 대한 테스트 작성 → 테스트 실패
GREEN: 통과시킬 최소 코드 작성 → 테스트 통과
이게 너의 트레이서 불릿 — 경로가 끝에서 끝까지 작동함을 증명.
3. 증분 루프(Incremental Loop)
남은 각 동작에 대해:
RED: 다음 테스트 작성 → 실패
GREEN: 통과시킬 최소 코드 → 통과
규칙:
- 한 번에 테스트 1개
- 현재 테스트를 통과시킬 만큼의 코드만
- 미래 테스트를 예상하지 마
- 관찰 가능한 동작에 테스트 집중
4. 리팩터
모든 테스트가 통과하면, 리팩터 후보를 찾아:
RED인 동안 절대 리팩터하지 마. GREEN에 먼저 도달.
RED evidence commit (pre-push gate)
이 repo 의 review-profile: code sprint 는 push 전에 RED commit 을 evidence 로
요구한다. pre-push scripts/hooks/check-tdd-cycle.sh 가 merge-base..HEAD 의
commit subject 를 검사하고, RED 표식이 없으면 push 를 차단한다. 방법론만 지키고
commit history 에 RED 흔적을 남기지 않으면 pre-push 에서 막힌다.
적용 조건: branch 가 sprint-N/... 이고 docs/sprints/sprint-N/contract.md 의
review-profile 이 code. 그 외 profile(docs/infra/security) 은 이 gate 를 건너뛴다.
허용 subject 표식:
[RED] ...
RED: ...
test: RED ...
test ... failing
세로 슬라이스대로 RED 커밋 → GREEN 커밋 순서를 유지하면 자연히 충족된다. hook
실패 시 SKIP_TDD_CYCLE=1 같은 skip 은 사용자 명시 승인 없이 쓰지 마라.
계약 SOT (적용 조건 / 예외 전체): memory/workflow/tdd/memory.md.
사이클별 체크리스트
[ ] 테스트가 구현이 아니라 동작을 기술
[ ] 테스트가 공개 인터페이스만 사용
[ ] 테스트가 내부 리팩터에서 살아남을 것
[ ] 코드가 이 테스트에 대해 최소
[ ] 추측성 기능이 추가되지 않음