← 염승준
04

테스트를 설계 문제로 다루기

라이브러리에선 회귀를 증명하려고, 어드민에선 API 없이 먼저 출발하려고.

문제
  • npm에 배포하는 라이브러리라 "내가 안 깨뜨렸다"를 스스로 증명해야 했음
  • 실무 어드민은 백엔드 API가 확정되기 전에 프론트엔드를 먼저 시작해야 했음
해결
  • 함수마다 기본 동작·엣지 케이스·에러 처리를 검증. 클립보드는 전역 모킹, 타이머는 가짜 타이머
  • 테스트하기 어려운 함수는 테스트를 억지로 짜기보다 환경 의존부터 분리
  • zod 스키마를 API 계약 초안으로 두고, MSW가 실제 엔드포인트 URL을 가로채게 해 앱 코드에 목 분기를 두지 않음
결과
  • 라이브러리 커버리지 약 90%, CI에서 타입 검사·테스트 자동 실행
  • 환경변수 토글만으로 실서버 전환. 계약이 바뀌면 스키마 한 곳만 수정

개인 라이브러리에서 — 회귀를 스스로 증명하기

남이 쓸 코드를 npm에 배포하다 보니 "내가 안 깨뜨렸다"를 스스로 증명해야 했습니다. Vitest로 함수마다 기본 동작·엣지 케이스·에러 처리를 검증해 커버리지 약 90%를 확보하고, 타입 검사와 테스트를 CI에서 자동 실행해 배포 전에 회귀를 막았습니다.

까다로웠던 건 환경에 의존하는 함수들이었습니다. 클립보드 복사는 최신 API와 레거시 방식 두 경로를 모두 검증해야 해서 전역을 모킹했고, sleep 같은 타이머 함수는 가짜 타이머로 실제 대기 없이 비동기 타이밍을 확인했습니다.

테스트하기 어려운 함수는 대개 설계가 환경에 붙어 있다는 신호였습니다. 그럴 때는 테스트를 억지로 짜기보다 함수를 먼저 갈랐습니다.

실무 어드민에서 — API 없이 먼저 출발하기

백엔드 API가 확정되지 않은 시점에 프론트엔드를 먼저 시작해야 했습니다. zod 스키마를 API 계약 초안으로 정의하고, MSW가 실제 엔드포인트 URL을 가로채도록 구성했습니다.

핵심은 앱 코드에 목 분기를 남기지 않은 것입니다. if (isMock) 같은 조건이 코드에 들어가면 나중에 전부 걷어내야 하고, 걷어내는 과정에서 실서버 경로가 처음 실행됩니다. URL을 가로채는 방식이면 앱은 항상 진짜 요청을 보내고 있다고 믿으므로, 환경변수 토글만으로 실서버 전환이 끝납니다.

계약이 바뀌면 스키마 한 곳만 고치면 목과 런타임 검증이 함께 따라옵니다.