테스트 자동화 프레임워크 선택: Selenium vs Playwright vs Cypress

테스트 자동화 프레임워크 선택: Selenium vs Playwright vs Cypress

프레임워크 전쟁의 시작

월요일 오전. 슬랙에 CTO 메시지가 떴다.

“J님, Playwright 도입 검토 좀 해주세요.”

커피 한 모금도 안 마셨다. 머리가 복잡해졌다.

우리 자동화 프레임워크는 Selenium 기반이다. 4년 전에 내가 직접 구축했다. 테스트 케이스 1200개. 커버리지 65%. 매일 밤 돌아간다. 문제없이 돌아간다.

그런데 최근 개발자들이 계속 물어본다.

“Playwright는 왜 안 써요?” “Cypress가 더 빠르다던데요?” “Selenium은 옛날 거 아닌가요?”

짜증 났다. 그래서 제대로 정리하기로 했다.

Selenium: 내 4년의 동반자

우리 프레임워크는 Selenium + Python + Pytest다.

현재 상태:

  • 테스트 케이스: 1200개
  • 실행 시간: 약 3시간 (병렬 처리)
  • 안정성: 85% (flaky test 때문에)
  • 유지보수 시간: 주 10시간

솔직히 말하면 Selenium은 늙었다. 2004년부터 있었다. 거의 20년 됐다.

장점이 명확하다:

  1. 브라우저 지원이 최고다. Chrome, Firefox, Safari, Edge, 심지어 IE도 된다. 우리 고객 중 10%가 아직 IE 쓴다. 믿기지 않지만 사실이다.

  2. 생태계가 방대하다. 스택오버플로우에 답이 다 있다. 에러 메시지 복사해서 검색하면 해결법 나온다. 이게 얼마나 중요한지 모른다.

  3. 언어 선택의 자유. Python, Java, JavaScript, C#, Ruby. 뭐든 된다. 우리는 Python이다. 백엔드팀이 Python이라 코드 공유가 쉽다.

  4. 모바일도 된다. Appium이 Selenium 기반이다. 웹/앱 자동화 프레임워크 통합이 가능하다.

단점도 분명하다:

  1. 느리다. WebDriver 통신 방식이 문제다. 브라우저 ↔ WebDriver ↔ 테스트 코드. 중간 단계가 많다. 네트워크 레이턴시가 쌓인다.

  2. 셋업이 복잡하다. ChromeDriver 버전 맞추기가 지옥이다. Chrome 자동 업데이트되면 테스트 깨진다. CI 환경에서 드라이버 관리가 일이다.

  3. Flaky test 지옥. time.sleep(2) 이딴 게 코드에 수십 개다. 요소 로딩 타이밍 잡기가 어렵다. WebDriverWait 써도 완벽하지 않다.

  4. 에러 메시지가 불친절하다. “Element not found”. 그래서 어디서 왜 없는 건데? 디버깅에 시간 배로 든다.

매주 flaky test 잡는데 3시간 쓴다. 진짜 스트레스다.

Playwright: 떠오르는 강자

팀 막내가 사이드 프로젝트로 Playwright 써봤다고 했다.

“진짜 빨라요. 셋업도 쉽고요.”

그래서 직접 테스트해봤다. 일주일 동안 POC 진행했다.

첫인상이 강렬했다:

# Selenium
driver = webdriver.Chrome()
driver.get("https://example.com")
element = driver.find_element(By.ID, "button")
element.click()

# Playwright
page.goto("https://example.com")
page.click("#button")

코드가 간결하다. 보일러플레이트가 적다.

장점:

  1. 속도가 미쳤다. 브라우저랑 직접 통신한다. CDP(Chrome DevTools Protocol) 쓴다. WebDriver 없다. 같은 테스트가 40% 빠르다.

  2. 자동 대기가 똑똑하다. page.click()하면 알아서 요소 나타날 때까지 기다린다. time.sleep() 필요 없다. Flaky test가 확 줄어든다.

  3. 셋업이 쉽다. playwright install 하면 끝이다. 브라우저 바이너리를 직접 다운로드한다. 버전 걱정 없다.

  4. 병렬 처리가 강력하다. 브라우저 컨텍스트 격리가 잘 된다. 세션 충돌 없다. 테스트 속도가 배로 빨라진다.

  5. 디버깅 툴이 좋다. Playwright Inspector가 있다. 스텝별로 실행하고 요소 하이라이트된다. 스크린샷 자동 저장. 비디오 녹화도 된다.

  6. API 테스트도 된다. playwright.request로 API 호출 가능하다. E2E + API 통합 테스트가 한 프레임워크에서 된다.

단점:

  1. 브라우저 제한. Chromium, Firefox, WebKit만 된다. IE 안 된다. Safari는 WebKit이지만 진짜 Safari랑 다르다. 우리 10% 고객은?

  2. 생태계가 작다. 2020년에 나왔다. 4년밖에 안 됐다. 스택오버플로우 답변이 적다. 이상한 버그 만나면 혼자 해결해야 한다.

  3. 학습 곡선. Selenium 아는 사람이 많다. Playwright는 새로 배워야 한다. 팀 온보딩 시간이 든다.

  4. Microsoft 의존. MS가 만들었다. 오픈소스지만 결국 MS 생태계다. TypeScript 푸시가 강하다. Python 지원은 2등이다.

실제로 로그인 테스트 5개를 마이그레이션 해봤다.

결과:

  • 작성 시간: Selenium 3시간 → Playwright 1.5시간
  • 실행 속도: 45초 → 18초
  • Flaky 발생: 3회 → 0회

솔직히 놀랐다.

Cypress: 프론트엔드의 사랑

프론트엔드 개발자들은 Cypress를 좋아한다.

“저희 로컬에서 개발하면서 바로 테스트 돌려요.”

그게 Cypress의 철학이다. 개발자 경험에 집중한다.

특징:

  1. 실시간 리로딩. 코드 저장하면 브라우저가 자동으로 테스트 다시 돌린다. TDD 하기 좋다.

  2. 타임 트래블. 테스트 각 단계로 돌아갈 수 있다. DOM 스냅샷이 저장된다. 디버깅이 직관적이다.

  3. 네트워크 모킹이 쉽다. cy.intercept()로 API 응답을 가짜로 만든다. 백엔드 없이 프론트 테스트 가능하다.

  4. DX가 최고다. 문서가 친절하다. 에러 메시지가 구체적이다. 커뮤니티가 활발하다.

치명적 단점:

  1. 단일 도메인만 된다. 탭 전환 안 된다. 다른 도메인 이동하면 꼬인다. OAuth 로그인 테스트가 어렵다. 우리는 Google 로그인 쓴다. 불가능하다.

  2. 백엔드 테스트 약하다. API 테스트가 메인이 아니다. 프론트 중심이다.

  3. 병렬 처리가 유료다. Cypress Dashboard 써야 한다. 월 75달러부터 시작이다. 오픈소스로는 순차 실행만 된다.

  4. 브라우저 제한. Chrome, Firefox, Edge만 된다. Safari 안 된다.

우리 테스트 시나리오 중 30%가 멀티 도메인이다. Cypress는 답이 안 나온다.

프론트 개발자들 로컬 테스트용으로는 좋다. E2E 메인 프레임워크로는 부족하다.

실전 비교: 같은 테스트를 세 가지로

공정한 비교를 위해 실험을 했다.

시나리오: 로그인 → 대시보드 → 리포트 생성 → 다운로드 → 로그아웃

복잡도 중간. 우리 일반적 테스트다.

개발 시간:

  • Selenium: 4시간 (웨이트 튜닝에 1시간)
  • Playwright: 2시간
  • Cypress: 3시간 (다운로드 처리 까다로움)

실행 시간 (10회 평균):

  • Selenium: 42초
  • Playwright: 18초
  • Cypress: 25초

안정성 (50회 반복):

  • Selenium: 43회 성공 (86%)
  • Playwright: 50회 성공 (100%)
  • Cypress: 48회 성공 (96%)

코드 라인 수:

  • Selenium: 85줄
  • Playwright: 52줄
  • Cypress: 58줄

Playwright가 압도적이었다.

디버깅 시간 (의도적 버그 삽입):

  • Selenium: 평균 12분
  • Playwright: 평균 5분 (Inspector 덕분)
  • Cypress: 평균 6분 (타임 트래블 덕분)

숫자는 거짓말 안 한다.

마이그레이션 시뮬레이션

CTO가 원한 건 현실적 검토였다.

우리 상황:

  • 테스트 케이스: 1200개
  • 일일 커밋: 평균 25개
  • QA 팀: 4명 (자동화 담당 나 포함 2명)
  • 예산: 넉넉하지 않음
  • 타임라인: 분기별 목표 있음

Playwright로 전환 시:

Phase 1 (1개월):

  • 신규 기능 테스트만 Playwright로 작성
  • 기존 Selenium 유지
  • 병렬 운영
  • 학습 기간 포함

Phase 2 (2개월):

  • Critical path 20% 마이그레이션
  • 로그인, 결제, 회원가입 등
  • 성공률 모니터링
  • 팀 피드백 수집

Phase 3 (3개월):

  • 나머지 80% 점진적 전환
  • 주 30개씩 변환
  • Selenium deprecated 공지

총 소요: 6개월

비용:

  • 개발 시간: 480시간 (나 + 동료)
  • 급여 환산: 약 2400만원
  • CI 인프라 조정: 300만원
  • 교육/학습: 무형 비용

기대 효과:

  • 테스트 실행 시간: 3시간 → 1.2시간 (60% 단축)
  • Flaky test: 15% → 3% (80% 감소)
  • 유지보수 시간: 주 10시간 → 4시간 (60% 단축)

ROI를 계산했다.

6개월 투자로 이후 매주 6시간 절약. 1년이면 312시간. 내 시급 3만원으로 계산하면 936만원. 2년이면 1872만원.

투자 대비 회수 기간: 약 18개월.

나쁘지 않다.

팀 설득 작업

수요일 오후. QA 팀 회의.

“Playwright로 가는 거 어떻게 생각해?”

반응이 갈렸다.

매뉴얼 QA 출신 후배 (경력 2년): “Selenium도 이제 겨우 익숙해졌는데요… 또 배워야 해요?”

자동화 동료 (경력 5년): “좋긴 한데 IE 고객은요? 그냥 Selenium 4로 업그레이드하는 건요?”

신입 (경력 6개월): “저는 Playwright가 더 쉬운 것 같던데요. 학원에서 배울 때도 그게 더 쉬웠어요.”

각자 입장이 다르다.

개발팀 회의도 했다.

프론트 리드: “좋아요. 저희는 Cypress 쓰고, QA는 Playwright 쓰고. 통합은 안 해요?”

백엔드 리드: “E2E가 빨라지면 저희 PR 리뷰가 빨라지나요? 그럼 찬성이에요.”

DevOps: “CI 파이프라인 다시 짜야 하는 거죠? 시간 주세요.”

CTO한테 보고했다.

“투자 대비 효과가 명확하네요. 진행하세요. 단, 기존 테스트 안정성 떨어지면 안 됩니다.”

압박이다.

현실적 결론

금요일 저녁. 결정을 내렸다.

선택: Playwright

이유:

  1. 속도와 안정성. 숫자가 증명한다. 논쟁 여지 없다.

  2. 장기 투자. 6개월 고생하면 이후 2년 편하다. 이직해도 이력서에 최신 기술 쓴다.

  3. 팀 성장. 새 기술 배우는 게 동기부여된다. 다들 지루해하고 있었다.

  4. 트렌드. 2024년 기준 Playwright가 대세다. GitHub 스타 60k. Selenium 30k 정체 중.

단, 조건:

  1. IE 고객 예외 처리. 해당 기능만 Selenium 유지. 별도 파이프라인. 10%를 위해 90% 희생 안 한다.

  2. 점진적 전환. 빅뱅 금지. 한 번에 바꾸면 망한다. 스프린트당 5% 목표.

  3. 롤백 플랜. 실패하면 Selenium 복귀. 자존심 버린다.

  4. 문서화. 모든 변경사항 기록. 다음 사람을 위해.

Selenium을 버리는 게 아니다:

  • 모바일 테스트(Appium)는 계속 Selenium 기반
  • 레거시 브라우저 테스트는 유지
  • 스킬은 여전히 가치 있다

Cypress는?

프론트팀 로컬 개발용으로 권장한다. E2E 메인은 Playwright. 역할이 다르다.

월요일부터 시작한다. 첫 주는 학습. 튜토리얼 돌리고 팀 세션 연다.

두려움 반 설렘 반이다.

1주일 후

실제로 시작했다.

신규 기능 “알림 설정” 테스트를 Playwright로 짰다.

소요 시간:

  • 예상: 3시간
  • 실제: 5시간

처음이라 헤맸다. 하지만 결과는 좋았다.

Playwright 코드:

def test_notification_settings(page):
    page.goto("/settings")
    page.click("text=알림 설정")
    page.check("#email-notification")
    page.click("button:has-text('저장')")
    
    # 자동 대기. time.sleep 없음.
    expect(page.locator(".success-message")).to_be_visible()

깔끔하다. 읽기 쉽다.

같은 테스트 Selenium이었으면:

def test_notification_settings(driver):
    driver.get("/settings")
    WebDriverWait(driver, 10).until(
        EC.element_to_be_clickable((By.LINK_TEXT, "알림 설정"))
    ).click()
    
    time.sleep(1)  # 페이지 전환 대기
    
    checkbox = WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.ID, "email-notification"))
    )
    checkbox.click()
    
    time.sleep(0.5)  # 체크박스 애니메이션
    
    driver.find_element(By.XPATH, "//button[contains(text(), '저장')]").click()
    
    time.sleep(2)  # 저장 처리 대기
    
    message = WebDriverWait(driver, 10).until(
        EC.visibility_of_element_located((By.CLASS_NAME, "success-message"))
    )
    assert message.is_displayed()

차이가 명확하다.

팀 동료가 코드 리뷰했다.

“오… 진짜 짧네요. 이게 돌아가요?”

돌아간다. 50번 돌렸다. 50번 성공했다.

후배가 물었다.

“저도 다음 테스트는 Playwright로 해봐도 돼요?”

“해봐. 막히면 불러.”

변화가 시작됐다.

2주 후 첫 위기

CI에서 Playwright 테스트가 터졌다.

로컬에서는 되는데 CI에서 실패한다. 클래식한 문제다.

에러:

browserType.launch: Executable doesn't exist at /home/runner/.cache/ms-playwright/chromium-1097/chrome-linux/chrome

브라우저 바이너리가 없다.

CI 설정 문제였다.

해결:

# .github/workflows/test.yml
- name: Install Playwright
  run: |
    pip install playwright
    playwright install --with-deps chromium

--with-deps 옵션이 핵심이다. 시스템 의존성까지 설치한다.

다시 돌렸다. 성공했다.

하지만 시간이 오래 걸렸다.

CI 실행 시간:

  • Selenium: 15분
  • Playwright: 22분

뭐가 문제인가.

프로파일링 했다. 브라우저 설치 시간이 7분이었다.

최적화:

- name: Cache Playwright browsers
  uses: actions/cache@v3
  with:
    path: ~/.cache/ms-playwright
    key: playwright-${{ hashFiles('**/requirements.txt') }}

캐싱 추가했다.

결과:

  • 첫 실행: 22분
  • 이후 실행: 8분

Selenium보다 빠르다.

DevOps 담당자가 만족했다.

“CI 비용도 줄겠는데요?”

GitHub Actions는 분 단위 과금이다. 월 500달러 쓰고 있었다. 40% 단축이면 월 200달러 절약이다.

연간 2400달러. 320만원.

부수 효과였다.

1개월 후 중간 점검

신규 테스트 25개를 Playwright로 짰다.

통계:

  • 평균 작성 시간: 2.2시간 (Selenium 대비 40% 단축)
  • 평균 실행 시간: 15초 (Selenium 대비 65% 단축)
  • Flaky 발생: 0건
  • 팀 만족도: 5점 만점에 4.2점

좋다. 하지만 문제도 있었다.

이슈 1: 스크린샷 용량

Playwright는 실패 시 자동으로 스크린샷을 찍는다. 좋은 기능이다.

하지만 CI 아티팩트 용량이 터졌다.

해결:

# pytest.ini
[pytest]
playwright_screenshot = only-on-failure
playwright_video = retain-on-failure

필요한 것만 저장한다.

이슈 2: 팀 학습 곡선

매뉴얼 QA 출신 후배가 고전했다.

“Locator가 뭐예요? Selector랑 다른 건가요?”

Playwright의 개념이 Selenium과 달랐다.

해결:

매주 금요일 1시간 세션을 열었다.

  • Week 1: Locator vs Selector
  • Week 2: Auto-waiting 원리
  • Week 3: API testing
  • Week 4: 디버깅 Tips

효과가 있었다. 후배가 처음으로 Playwright 테스트를 혼자 완성했다.

“생각보다 쉬워요. 웨이트 신경 안 써도 되니까 편해요.”

성장이 보였다.

이슈 3: Selenium 테스트 방치

신규 테스트는 Playwright로 짠다. 기존 Selenium 테스트는 그대로다.

문제는 유지보수였다.

개발자가 UI를 바꾸면 Selenium 테스트가 깨진다. 고치기 귀찮다. Playwright로 다시 짜고 싶다.

하지만 계획은 점진적 전환이었다.

해결:

우선순위를 정했다.

  1. Critical path (결제, 로그인): 즉시 전환
  2. 자주 깨지는 테스트: 다음 분기
  3. 안정적인 테스트: 마지막

급하게 하지 않는다.

CTO한테 중간 보고했다.

“순항 중입니다. 예상보다 빠릅니다.”

“좋네요. 근데 ROI는 언제 나와요?”

“3개월 후부터 유지보수 시간이 줄어들 겁니다.”

“기대하겠습니다.”

압박은 계속된다.

3개월 후 전환점

기존 Selenium 테스트 중 200개를 Playwright로 전환했다.

전체의 약 17%. 목표치(15%) 초과했다.

효과가 나타났다:

유지보수 시간:

  • 이전: 주 10시간
  • 현재: 주 6.5시간

Flaky test 비율:

  • 이전: 15%
  • 현재: 8%

CI 실행 시간:

  • 이전: 180분
  • 현재: 145분

숫자로 증명됐다.

결정적 사건:

대규모 UI 리뉴얼이 있었다.

디자인 시스템 전면 교체. 버튼, 입력창, 모달 전부 바뀌었다.

Selenium 테스트 1000개가 다 깨졌다.

끔찍했다.

복구 시간 예상:

  • Selenium: 약 80시간 (ID, 클래스명 다 바뀜)
  • Playwright: 약 30시간 (텍스트 기반 Locator 많이 씀)

실제로는:

  • Selenium: 75시간 (4일)
  • Playwright: 25시간 (1.5일)

차이가 극명했다.

CTO가 인정했다.

“전환 잘한 것 같네요.”

팀 사기도 올랐다.

“다음 분기엔 더 많이 전환해볼까요?”

속도가 붙었다.

남은 과제들

아직 해결 못한 것들이 있다.

1. IE 고객

여전히 10%다. 줄지 않는다.

해당 기능은 Selenium 유지 중이다. 별도 파이프라인 돌린다.

언젠가는 IE 지원 중단할 것이다. 그때까지는 이중 운영이다.

2. 모바일 앱

Appium은 여전히 Selenium 기반이다.

Playwright에 모바일 지원이 실험 단계에 있다. 아직 프로덕션 레디는 아니다.

당분간은 분