쿠폰 계산 버그를 고치면서 Claude에게 구현과 테스트를 한 번에 맡기면 같은 요구사항 오해가 양쪽에 들어갈 수 있습니다. Plan Mode에서 규칙과 기존 테스트를 먼저 읽히고, 경계값 표와 실패할 테스트를 코드 수정 전에 받는 편이 낫습니다. 사람이 기대값을 확정한 뒤 단위, 통합, 브라우저 검증을 필요한 만큼만 엽니다.
핵심 가장 빠른 정적 검사부터 작은 로직, 구성요소 통합, 실제 사용자 흐름과 사람 검수 순서로 검사를 배치합니다. 구현자와 다른 관점의 테스트와 리뷰가 있어야 같은 오류를 함께 승인하는 위험이 줄어듭니다.
첫 층은 빠르고 결정적이어야 한다
문법, 포맷, 타입과 정적 분석은 피드백이 빠르고 실패 원인이 비교적 명확합니다. 변경한 파일에 맞는 검사를 먼저 실행하면 뒤의 비싼 테스트가 단순 오류로 낭비되는 일을 줄일 수 있습니다.
생성된 파일, 의존성 잠금과 마이그레이션처럼 코드 밖 변경도 차이 검사에 포함합니다. 테스트 명령 자체가 성공 코드를 반환하는지와 실제로 테스트를 발견했는지도 확인합니다.
단위와 통합 테스트의 역할을 섞지 않는다
단위 테스트는 작은 규칙을 격리해 빠르게 확인합니다. 정상값뿐 아니라 빈 값, 경계값, 권한 거부와 외부 실패를 포함합니다. 통합 테스트는 데이터베이스, 큐와 API처럼 구성요소 사이의 계약을 확인합니다.
에이전트에게 테스트 수만 목표로 주면 의미 없는 단언과 구현 세부사항에 묶인 테스트가 늘 수 있습니다. 실패하면 어떤 사용자 위험을 막는 테스트인지 설명할 수 있어야 합니다.
E2E는 적지만 중요한 흐름에 집중한다
브라우저 테스트는 로그인, 결제, 저장과 배포처럼 사용자가 끝까지 완료해야 하는 흐름을 검증합니다. 모든 화면 요소를 자동화하려 하면 느리고 불안정해질 수 있어 핵심 경로와 치명적인 회귀에 집중합니다.
실패 시 스크린샷, 콘솔과 네트워크 기록을 남기면 에이전트가 원인을 좁히기 쉽습니다. 하지만 시각적 균형, 문장 의미와 실제 데이터의 타당성은 사람이 확인해야 합니다.
테스트를 작성한 에이전트가 최종 판정까지 맡지 않는다
같은 에이전트가 구현과 테스트를 모두 만들면 요구사항 오해가 양쪽에 반복될 수 있습니다. 독립 리뷰, 기존 회귀 테스트와 사람의 수용 기준을 조합합니다. 중요한 변경은 구현자가 예상하지 못한 실패 시나리오를 별도로 요청합니다.
테스트가 통과하면 변경 차이와 미실행 영역을 요약합니다. 통과했다는 한 줄보다 무엇을 검사했고 무엇은 검사하지 못했는지가 배포 판단에 더 유용합니다.
실패 테스트를 먼저 받는 대화
예시 세션은 쿠폰 할인 상한 버그를 다룹니다. Plan Mode에서 규칙과 기존 테스트를 읽힌 뒤, 구현을 건드리지 않고 실패 표부터 받습니다.
claude --permission-mode plan
CLAUDE.md, package.json, src/coupon/calculate.ts, tests/coupon/**를 읽으세요.
구현과 테스트를 수정하지 마세요.
반환 형식:
- 사용자 규칙과 코드의 차이
- 단위 테스트 경계값
- API 통합 테스트 한 건
- 브라우저로 확인할 핵심 흐름
- 각 계층이 잡지 못하는 영역
운영 DB와 외부 결제 도구는 사용하지 마세요.
사람은 기대값을 확정하고 편집을 좁힙니다
할인 상한이 주문 전체 기준인지 상품별 기준인지 문서가 충돌하면 Claude가 추측하게 두지 않습니다. 사람이 제품 규칙을 확인한 뒤 “주문 전체 상한으로 확정합니다. 수정 전 실패하는 단위 테스트를 먼저 추가하고 실패 로그를 보여준 다음 최소 구현을 고치세요”라고 이어갑니다.
예상 결과는 새 테스트가 수정 전 실패하고 수정 후 통과하는 것입니다. 프로젝트의 단위·통합 명령을 실행한 뒤 `git diff --check`, `git diff -- src/coupon tests/coupon`으로 구현과 테스트가 같은 잘못된 상수를 공유하지 않는지 봅니다. E2E가 외부 결제를 실제 호출하거나 테스트 데이터 정리가 보장되지 않으면 그 계층에서 멈춥니다. 로그가 길어 메인 대화를 압도하면 테스트 실행만 서브에이전트에 맡기고 실패 요약을 받습니다.
할인 계산 오류는 세 번째 층에서 잡혔다
가상의 장바구니 할인 사례를 따라가 봅시다. 타입 검사와 기존 단위 테스트는 통과한 상태입니다. 할인 함수는 입력한 쿠폰 금액을 정확히 뺐기 때문입니다. 하지만 통합 테스트에서 쿠폰 적용 뒤 배송비 계산이 이전 소계를 다시 읽어 최종 금액이 잘못 계산되는 문제가 드러납니다. 함수 하나의 정답과 주문 전체의 정답이 달랐던 것입니다.
통합 오류를 고친 뒤 브라우저 테스트에서는 결제 화면의 합계와 서버 응답이 같았고 주문 행도 한 건만 생겼습니다. 마지막 사람 검수에서 모바일 화면의 할인 안내가 접혀 보이지 않는 문제가 발견됐습니다. 같은 변경도 정적 검사, 단위, 통합, 브라우저, 사람 검수가 서로 다른 결함을 잡았습니다.
검증 결과는 계층별 산출물로 남긴다
완료 보고에는 “전체 테스트 통과” 대신 각 층이 무엇을 확인했는지 적습니다.
정적 검사: 타입·린트 통과
단위: 기존 테스트 통과, 할인 경계값과 최대값 포함
통합: 쿠폰 뒤 배송비 재계산과 주문 합계 확인
브라우저: 중복 결제 없음, 화면·API 합계 일치
사람 검수: 작은 화면에서 할인 안내 노출 확인
미검증: 실제 결제사 샌드박스
어느 층이든 신뢰할 수 없으면 배포를 멈춘다
테스트가 실제 사례를 발견하지 못하거나, 재시도할 때만 통과하거나, 운영과 다른 가짜 응답에 지나치게 의존하면 초록색 결과를 승인 근거로 쓰지 않습니다. 결제사 샌드박스처럼 외부 검증이 필수인데 실행하지 못했다면 미완료로 남깁니다.
모든 변경에 모든 층이 필요한 것은 아닙니다. 문구 수정에 결제 통합 테스트를 새로 만들 이유는 없습니다. 다만 생략한 층과 이유를 설명할 수 있어야 하며, 실패 영향이 커질수록 더 바깥쪽 사용자 흐름까지 검증해야 합니다.
읽고 나서 확인하기
답을 떠올린 뒤 본문의 판단 기준과 비교해 보세요.
- 수정한 로직의 단위 테스트와 계층 사이 계약을 확인하는 통합 테스트를 구분합니다.
- 핵심 사용자 흐름만 E2E로 확인하고 모든 경우를 브라우저 테스트에 몰지 않습니다.
- 통과한 검사와 실행하지 못한 검사를 완료 보고에서 따로 적습니다.