E2E 테스트 도입기
E2E 테스트를 도입하면서 고려했던 점과 느꼈던 점들에 대해 알아봅니다.
개요
프론트엔드 환경에서 테스팅은 필수 요소입니다. 작성한 코드가 의도된 대로 작동하는지 확인하는 유닛 테스트부터, 실제 고객의 여정 전체를 검증하는 E2E 테스트까지 다양한 테스트 방법이 있습니다. 이 중에서도 E2E 테스트는 실제 사용자의 실행 환경과 거의 동일한 환경에서 테스트를 진행하기 때문에 실제로 발생하는 에러를 잡아낼 수 있다는 점에서 가장 중요하다고 생각합니다.
프로덕트에서 고객들이 가장 많이 사용하는 기능은 파일 번역입니다. 법률 도메인의 품질 측면에서 큰 강점을 갖고 있어서 변호사를 포함한 다양한 고객들이 구독형 요금제를 이용하고 있습니다. 하지만 서버와 Translation worker 등의 여러 이슈로 번역이 실패하는 경우가 종종 발생했고, 이는 자연스럽게 고객 문의의 증가로 이어졌습니다.
문제는 이러한 오류가 발생할 때 고객 문의를 받기 이전에 미리 확인하고 예방할 수 있는 프로세스가 없다는 것이었습니다. QA 팀이 없는 것도 한몫했습니다. 고객 문의에 하나하나 대응하고 직접 재현해보며 수정하는 과정은 번거롭고 개발 생산성을 저해하는 요인이었습니다. 이러한 문제를 해결하기 위해 클라이언트에서 발생할 수 있는 오류를 사전에 발견하고 예방할 수 있도록 E2E 테스트를 도입하고 자동화하기로 결정했습니다.
Playwright vs Cypress
E2E 테스트를 위한 라이브러리로는 대표적으로 Playwright (opens in a new tab)와 Cypress (opens in a new tab)가 있습니다. 이 두 가지 중 어떤 라이브러리를 사용할지에 대해 고민했습니다. 제가 생각한 주요 기준은 다음과 같습니다.
- 러닝커브가 높지 않아야 한다
- 병렬 테스트가 가능해야 한다
- 다양한 브라우저를 지원해야 한다
Cypress의 장단점
장점
- 러닝커브: 높지 않음 (
npx cypress open
으로 간편하게 앱 실행 (opens in a new tab)이 가능하며, 테스트용 GUI 기능이 강력함) - 디버깅 경험: 매우 우수함 (Time Travel 기능으로 각 단계별 DOM 스냅샷 확인 가능)
- 실시간 리로딩: 테스트 코드 변경 시 자동으로 테스트 재실행
- 커뮤니티: 활발한 커뮤니티와 풍부한 플러그인 생태계
단점
- 브라우저 지원:
Chromium
계열 브라우저와Firefox
에 한정 (WebKit(Safari)
: 실험 단계) - 병렬 테스트: 부분 지원 (유료 버전에 한정. 무료 사용 시 sorry-cypress (opens in a new tab) 등 별도 플러그인 필요)
- 아키텍처 제약: 브라우저 내부에서 실행되어 iframe이나 다중 탭 테스트에 제약
Playwright의 장단점
장점
- 브라우저 지원:
Chromium
,Firefox
,WebKit(Safari)
등 모든 주요 브라우저 지원 - 병렬 테스트: 기본 지원으로 빠른 테스트 실행
- Headless 모드: 기본적으로 Headless로 실행되어 CI 환경에 최적화
- API 테스트: 브라우저 없이도 API 테스트 가능
단점
- 디버깅: Cypress 대비 디버깅 경험이 상대적으로 제한적
- 러닝커브: 높지 않지만 Cypress 대비 초기 설정이 다소 복잡할 수 있음
최종 선택
우리 프로젝트에서는 다음과 같은 이유로 Playwright를 선택했습니다.
- 크로스 브라우저 테스트 필요성: 다양한 브라우저 환경의 고객들을 대상으로 하기 때문에 Safari 포함 모든 주요 브라우저에서의 테스트가 필수였음
- CI 최적화: GitHub Actions에서 빠른 테스트 실행을 위해 병렬 테스트 기본 지원이 중요했음
- 속도: 브라우저 환경이 필수인 Cypress와 비교했을 때 Headless 기반인 Playwright의 속도가 더 빠름
특히 병렬 테스트 지원 측면에서 Playwright는 playwright.config.ts
의 workers
설정만으로 간단하게 병렬 테스트를 구성할 수 있었습니다.
playwright.config.ts
import { defineConfig } from "@playwright/test"
export default defineConfig({
// Opt out of parallel tests on CI.
workers: process.env.CI ? 2 : undefined,
// ...
})
테스트 시나리오 작성
E2E 테스트의 시나리오는 기획서를 기반으로 작성했습니다.
- 테스트별로 다른 언어쌍, 도메인 기반 실행 (법률, 특허, 일반 번역)
.docx
및.pdf
파일 업로드, presigned URL API 호출 및 S3 업로드 로직 확인- 파일 업로드 완료 시 UI 확인
- 번역하기 버튼 클릭 후 SSE를 통한 실시간 번역 상태 확인
- 번역 완료 후 완료 파일 다운로드/삭제 기능 확인
이러한 접근 방식은 기획서의 변경사항을 빠르게 파악하고 테스트 코드에 반영할 수 있다는 장점이 있습니다.
Mocking과 실제 API를 조합한 테스트 코드 작성
Mock API를 사용한다는 것은 실제 백엔드 서버와 통신하는 것이 아니라, API가 무조건 특정 응답을 줄 것이라고 가정하고 작업하는 것입니다. 모든 테스트 상황이 실제와 동일할 때 E2E 테스트가 진정한 의미를 갖는다고 생각합니다. 특히 번역처럼 고객들이 실시간으로 사용하는 기능들은 실제 고객 환경과 동일한 조건에서 테스트하는 것이 중요하기 때문에 Mocking만으로는 원하는 결과를 얻기 어렵습니다.
하지만 다음과 같은 기능들은 Mock API를 사용하는 것이 더 빠르고 적절한 테스트 방법이라고 판단했습니다.
- 서비스 외부에 의존하는 특정 기능들 (예: 회원가입을 위한 이메일 인증)
- 사용자 행동에 따른 UI 변화/이벤트 발생 (예: 이메일 인증번호 6자리 입력 시 즉시 인증 확인 API 호출 등)
이 과정에서 로그인과 같은 반복적인 사전 작업들은 global setup (opens in a new tab) 설정으로 일원화했습니다. 그 외에도 테스트 코드를 작성하면서 다음과 같은 규칙을 정했습니다.
- 텍스트 기반 선택을 지양하고
data-testid
속성을 기반으로 Element를 선택: 텍스트 기반 선택 시 번역/UX 변경에 취약함 - 테스트 진행 후 번역 완료 파일 등 어떠한 기록도 남기지 않고 정리
- 실제 고객의 여정과 동일하므로 최대한 많은 시나리오를 고려하여 작성
테스트 코드를 작성하면서 비즈니스 로직에 대해 더 깊게 이해할 수 있었습니다.
GitHub Actions를 통한 테스트 자동화, Slackbot 연동
테스트 자동화는 GitHub Actions를 통해 진행했습니다. 다양한 브라우저 환경에서의 동작을 검증하기 위해
matrix
기능을 활용하여 Chromium
, Firefox
, WebKit(iOS Safari)
세 브라우저 환경에서 병렬 테스트를 진행했습니다.
번역 데이터를 기반으로 고객의 실제 사용 패턴과 유사한 테스트 환경을 구성하고, GitHub Actions의 cron을 활용하여
특정 시간마다 테스트를 실행하도록 자동화했습니다.

또한 테스트가 실패했을 때 실패한 Job의 링크를 Slackbot을 통해 전송하여 번역 오류에 즉각 대응할 수 있는 체계를 구축했습니다.

도입 결과
정량적 성과
E2E 테스트 도입 후 다음과 같은 정량적 성과가 나타났습니다.
- 고객 문의량: 동기간 대비 80% 감소
- 평균 버그 해결 시간: 최대 하루 → 반나절 이내로 단축
버그 탐지 및 해결
테스트를 작성하면서 아래와 같이 여러 중요한 버그들을 발견했고, 지속적으로 발견되는 새로운 버그들도 함께 수정하고 있습니다.
백엔드 영역
- SSE 연결 불안정: 실시간 번역 상태 확인을 위한 SSE 연결이 여러 개 물려있을 때 간헐적으로 연결이 끊기는 문제 리포트 및 해결
- 로그인 에러: 로그인 API가 간헐적으로
404 Not Found
를 리턴하는 문제 리포트 및 해결
NLP 영역
- 캐싱 문제: 특정 엔진에서 번역 실행 후 다시 업로드를 할 경우 기존 번역 내역을 캐싱하여 성공하지만 기존 번역은 진행중으로 남아있던 문제 리포트 및 해결. 이 문제는 고객의 번역 사용량과 밀접한 관련이 있어서 특히 중요한 버그였는데, E2E 테스트가 아니라면 재현하기 어려운 버그였습니다.
마치며
백엔드와 비교했을 때 프론트엔드 영역에서는 특히 일이 많고 바쁠수록 테스팅의 중요성이 간과되는 경우가 많습니다. 당연히 기능 자체가 있어야 그 기능에 대한 테스트도 있는 것이기 때문에 바쁜 조직에서 테스트 코드는 사치처럼 느껴질 수 있습니다.
하지만 테스트 코드가 있고, 그 테스트 코드가 오류를 발견하고 수정하는 과정을 반복할 때 비로소 프로덕트의 완성도가 높아진다고 생각합니다. 또한 테스트 코드를 체계적으로 작성해두면 버그 발견부터 수정, 배포까지의 전체 프로세스가 단축되어 개발 생산성을 크게 개선할 수 있습니다.
특히 E2E 테스트는 단순히 버그를 잡는 것을 넘어서, 팀 전체의 생산성을 높이는 도구로도 활용할 수 있다는 것을 경험했습니다. 초기 구축 비용은 있지만, 장기적으로 보면 그 투자 대비 효과는 충분히 가치 있다고 확신합니다.
© Sangmin Park .