"빠른 테스트는 아래, 느린 테스트는 위, 느린 건 아주 조금만."
이기는 모양
Mike Cohn 이 2009년에 testing pyramid 를 그렸는데, 그림이 다른 거보다 더 잘 늙었어. 바닥은 빠른 unit test 가 넓게 — 수백 개, 각각 밀리초 단위로 돌아가. 그 위에 더 얇은 integration 띠 — 수십 개. 꼭대기에 critical flow 를 커버하는 E2E 몇 개.
이 모양은 세 가지 직교 축을 따라가 — 속도, 비용, 정밀도. Unit 은 빠르고, 싸고, 정밀도가 낮아 (실제 브라우저를 시뮬레이션하지 않으니까). E2E 는 느리고, 비싸고, 정밀도가 높아 (그게 실제 브라우저야). Pyramid 가 말하는 건: 테스트 예산의 대부분을 비용 낮은 데에 쓰고, 정밀도가 중요한 데에 살짝 얹어.
안티 패턴들
아이스크림 콘: E2E 잔뜩, integration 조금, unit 거의 없음. "수동 QA 가 Selenium 스크립트 짠다" 로 시작한 프로젝트에서 흔해. 결과: 45분 CI 파이프라인이 여전히 flaky.
모래시계: unit 잔뜩, E2E 잔뜩, integration 거의 없음. 다이어그램으로는 괜찮아 보이는데 실전에서 무너져 — 사용자 대면 regression 의 대부분은 중간 층에 숨어 있거든 (unit 통과, E2E 통과, 근데 두 모듈 사이 API 계약이 깨졌어).
트로피 (Kent C. Dodds): integration 위주. 이건 틀린 게 아냐 — integration 이 가장 가치 높은 층인 프로젝트에 대한 의도적 trade-off 야. 근데 Kent 가 그렇게 말했다고 무작정 따르는 건 직전 lesson 의 종교 문제랑 같아.
뭐가 뭐에 매핑돼
전형적인 React + Next.js 프로젝트라면:
- Unit (Vitest): pure function, reducer, util, custom hook (
renderHook으로), jsdom/happy-dom 에서 작게 렌더한 컴포넌트. - Integration (Vitest + MSW): mock 된 API 와 통신하는 컴포넌트, multi-component flow, 격리된 라우트 핸들러 테스트.
- E2E (Playwright): 핵심 사용자 여정 — 가입, 로그인, 구매 완료. regression 이 실제로 비용으로 이어지는 한두 개 흐름.
테스트 예산
테스트를 짜고 유지하는 데 쓸 수 있는 시간은 유한해. Pyramid 는 그걸 쓰는 한 방식, trophy 는 다른 방식, '대충 유용해 보이는 거' 는 또 다른 방식. 나쁜 결과는 잘못된 모양을 고른 게 아니라, 골랐다는 걸 인지하지 못한 거야. 의도적으로 고르고, 왜 그랬는지 적어두고, suite 가 아프기 시작하면 (느린 CI, flake, 낮은 signal) 다시 평가해.