테스트 코드 작성 전략

pxd XE그룹이 사내 회의실 예약 시스템 the-zero(The0)의 백엔드를 개발하며 정리한 테스트 코드 경험은, 테스트를 작성하는 이유를 크게 두 가지로 압축한다. 하나는 애플리케이션의 신뢰성 확보이고, 다른 하나는 이 코드를 나중에 다시 보게 될 미래의 동료와 미래의 자신을 위한 배려다. 테스트 없이 기존 기능과 새 기능이 뒤엉키며 코드가 점점 엉망이 되는 악순환은 실무에서 자주 겪는 문제이며, 테스트 코드는 리팩터링과 기능 추가에 대한 최소한의 안전장치로 작동해 이 악순환을 끊는다.

테스트 코드를 작성하는 과정 자체가 설계에도 영향을 준다. 유닛 테스트가 가능하려면 함수가 하나의 기능만 하도록 잘게 쪼개져야 하는데, 이 요구는 자연스럽게 다른 사람이 이해하기 쉬운 코드로 이어진다. Kent C. Dodds의 글을 인용해 정적 분석·유닛 테스트·통합 테스트·E2E 테스트로 쌓이는 테스트 피라미드 개념을 설명하는데, 위 단계로 갈수록 신뢰도는 높아지지만 비용과 시간도 함께 커지는 트레이드오프가 있다. E2E 테스트(Cypress)는 실제 구동 환경까지 검증해 신뢰도가 가장 높지만 작성 시간이 오래 걸리고 화면이 자주 바뀌면 셀렉터도 함께 수정해야 하는 유지보수 부담이 크다. 반대로 유닛/통합 테스트(Jest)는 빠르고 저렴하지만, 그렇다고 유닛 테스트만으로 전부를 대체하는 것은 바람직하지 않으며, 소프트웨어를 사용하는 방식과 유사한 테스트일수록 더 큰 신뢰를 준다는 원칙에 따라 여러 테스트 유형을 복합적으로 구성해야 한다.

테스트 코드 도입의 실질적 효과로는 함수를 잘게 나누며 얻는 사고의 확장, 사이드 이펙트 없이 버그를 빠르게 발견·수정하는 능력, 애플리케이션에 대한 신뢰를 바탕으로 리팩터링과 새로운 아이디어를 과감히 시도할 수 있는 여지가 꼽힌다. 완벽한 테스트 커버리지는 불가능하지만, 자신의 테스트 능력을 과신하지 않고 최소한의 안전장치를 마련하는 태도 자체가 실무에서 반복적으로 발견되는 버그를 줄이는 데 도움이 된다.

Playwright로 E2E 테스트 도입하기

Playwright는 실제 브라우저를 직접 실행해 클릭·입력·페이지 이동 같은 사용자 동작을 자동화하고 그 결과를 검증하는 E2E(End-to-End) 테스트 도구다. pxd XE 그룹이 사내 장비 관리 시스템을 만들며 실제로 도입한 경험에 따르면, Playwright의 장점은 "사용자가 이 화면에서 이 버튼을 누르면 다음 화면이 제대로 나오는가"를 확인하는 데 초점이 맞춰져 있어 테스트 코드 자체가 선언적이고 직관적이라는 점이다. 컴포넌트 단위 테스트보다 전체 사용자 흐름을 파악하며 QA를 진행하는 프로젝트 환경에 특히 적합했다.

설정은 `playwright.config.ts`에서 테스트 디렉토리·타임아웃·CI 재시도 횟수(CI 환경에서는 실패 시 재시도, 로컬은 재시도 없음) 등을 지정하고, `setup` 프로젝트(로그인 등 사전 작업)와 실제 테스트 프로젝트(`e2e-tests`)를 `dependencies`로 연결해 로그인이 완료된 이후에만 본 테스트가 실행되도록 구성한다. 구글 OAuth처럼 폼 입력(`fill`)만으로 로그인할 수 없는 인증 방식에서는 브라우저를 직접 열어(`headless: false`) 수동으로 로그인을 진행한 뒤 `page.context().storageState()`로 인증 상태를 파일에 저장하고, 이후 테스트들은 이 `storageState`를 재사용해 매번 로그인하지 않고 인증된 상태로 시작한다. 리다이렉트 완료를 기다릴 때는 `page.waitForURL()`에 URL 패턴 검증 콜백과 넉넉한 타임아웃(예: 5분)을 주고, 타임아웃 발생 시에도 현재 페이지 URL을 다시 확인해 실제로는 로그인이 끝났는지 재확인하는 예외 처리가 실무적으로 유용했다.

Playwright 도입 후 체감한 장점은 세 가지다. ① 코드가 직관적이라 초기 진입 장벽이 낮다. ② 목록 조회·필터·상세 이동 같은 실제 사용자 흐름을 마우스로 누르는 것과 동일한 방식으로 검증할 수 있다. ③ 대여 중/사용 가능/수리 중 같은 상태 뱃지의 텍스트·컬러 변화 검증에 적합하다. 반면 바로 적용하기 어려웠던 이유도 있었다. UI 변경이 잦은 서비스는 초기에 테스트를 붙이면 오히려 테스트 코드 유지·수정 부담이 커지고, 데이터 준비가 까다로운 프로젝트는 구현 단계보다 기능이 모두 붙은 뒤 최종 확인 용도로 붙이는 편이 더 현실적이었다.

핵심 내용

  • 테스트 코드를 쓰는 두 가지 이유: 애플리케이션 신뢰성 확보, 미래의 동료/자신을 위한 가독성 확보
  • 유닛 테스트를 위해 함수를 잘게 쪼개는 과정 자체가 이해하기 쉬운 코드 설계로 이어짐
  • 테스트 피라미드(정적 분석-유닛-통합-E2E): 위로 갈수록 신뢰도는 높지만 비용·시간이 커지는 트레이드오프
  • E2E(Cypress)는 신뢰도가 높지만 작성 시간이 길고 UI 변경 시 셀렉터 유지보수 부담이 큼
  • 유닛 테스트만으로는 부족 — 소프트웨어의 실제 사용 방식과 유사한 테스트일수록 더 큰 신뢰를 준다는 원칙에 따라 복합적으로 구성
  • 효과: 사고의 확장, 사이드 이펙트 없는 빠른 버그 수정, 리팩터링에 대한 자신감 확보
  • Playwright: 실제 브라우저를 실행해 사용자 동작을 자동화하는 E2E 도구, 선언적 코드와 실제 사용자 시나리오 검증이 강점
  • Playwright `storageState`로 인증 상태를 파일 저장 → OAuth처럼 fill로 처리 안 되는 로그인도 setup 프로젝트로 1회만 수행 후 재사용
  • E2E 테스트는 UI 변경이 잦은 초기 개발 단계보다 기능 구현 완료 후 최종 확인 단계에 붙이는 편이 유지보수 부담이 적음

관련 개념

출처

최종 업데이트: 2026-09-07 | 출처 2개