Playwright 이 Selenium 보다 더 나은 주요 이유
항목 |
Playwright |
Selenium |
최신 웹 호환성 |
SPA, 반응형, 최신 프론트엔드 대응이 뛰어남 |
일부 최신 UI 대응 어려움 |
지원 브라우저 |
크롬/파폭/웹킷(사파리)/엣지 등 모두 |
크롬/엣지/파폭/사파리 |
실행 속도 |
빠름 (auto-wait 내장, 멀티 브라우저 기본 병렬화) |
상대적으로 느림, wait 직접 조절 필요 |
안정성 |
flaky test(랜덤 실패) 현상 적음, 자동대기 |
wait 명시적 추가 필요, flaky 가능성 |
API 구조 |
Modern(체이닝, Promise), 간단함 |
전통적인 WebDriver 방식 |
멀티브라우저 |
크롬, 파폭, 엣지, 웹킷(사파리) 완벽 지원 |
사파리는 맥에서만 부분 지원 |
병렬/분산 |
기본 지원, 매우 쉽고 빠름 |
xdist 등 외부 플러그인 필요 |
모바일/디바이스 |
모바일 가상환경, 위치/네트워크 등 세밀하게 제어 가능 |
User-Agent, 해상도만 에뮬 (제한적) |
테스트코드 간결성 |
더 직관적, 빠르게 작성 가능 |
다소 장황, wait 등 추가코드 많음 |
파일/프레임 지원 |
iframe, 파일업로드 등 복잡동작도 기본 지원 |
상대적으로 번거로움 |
최신 웹 대응 |
최신 웹표준/SPA/PWA 등 완벽 대응 |
일부 신기능은 별도 wait 필요 |
오픈소스, 커뮤니티 |
성장세/도입 빠름, MS/대기업 도입↑ |
레거시/대규모 프로젝트에서 강세 |
구조/학습 난이도 비교
항목 |
Playwright |
Selenium |
문법 스타일 |
함수형/체이닝/Promise 스타일(간결) |
전통적(객체+함수+상수 조합) |
대기 처리 |
모든 액션에서 자동 대기 내장 |
수동(wait, sleep, WebDriverWait 등 필요) |
요소 탐색 |
fill("#id"), click(".class"), text="..." |
By.ID, By.XPATH, By.CSS_SELECTOR 등 다양 |
코드 길이 |
더 짧고 직관적, 중복 적음 |
케이스 복잡할수록 길어짐, 중복 많음 |
비개발자 난이도 |
CSS 셀렉터만 알면 따라하기 훨씬 쉬움 |
기초적 Python 지식 필요, 요소선택/대기 이해 |
실패율(Flaky) |
auto-wait로 대부분 안정적 |
동적사이트/SPA 등에서 실패 확률 상대적으로 높음 |
셀레니움을 “계속” 쓰는 것이 나은 예외 상황
- 이미 셀레니움 기반 테스트 자산/코드/인프라가 방대한 조직 (마이그레이션 비용·리스크 고려)
- 반드시 특정 커스텀 브라우저/환경 지원이 필요한 경우
- 내부 툴, 전통적 조직 등에서 Selenium에 대한 경험치/문서가 압도적으로 많은 경우
동일한 테스트코드를 두 프레임워크에서 공유/재사용하는 것은 구조/코드가 달라서 불가
서로 다른 py 파일/테스트 모듈에서 각각 호출
실무 적용 예시
패턴 |
활용 예 |
신규/빠른 자동화 |
Playwright 추천 (최신 SPA, 반응형 등) |
기존 코드 활용 |
Selenium 유지, 필요시 Playwright로 이관 |
크로스브라우저 강화 |
Playwright (웹킷, 모바일 등까지 확장) |
대규모 병렬테스트 |
Playwright (병렬화/분산이 더 쉬움) |
셀레니움 코드(예시)
driver = webdriver.Chrome()
driver.get("https://example.com")
driver.find_element(By.ID, "login").click()
driver.find_element(By.NAME, "userid").send_keys("test")
driver.find_element(By.NAME, "password").send_keys("pw")
driver.find_element(By.ID, "submit").click()
driver.quit()
Playwright 변환 예시
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
page = browser.new_page()
page.goto("https://example.com")
page.click("#login")
page.fill("[name=userid]", "test")
page.fill("[name=password]", "pw")
page.click("#submit")
browser.close()
TC 예시
1. https://example.com 접속
2. 이메일 input에 "test@domain.com" 입력
3. 비밀번호 input에 "pw1234" 입력
4. 로그인(Confirm) 버튼 클릭
5. 로그인 성공 후 대시보드로 이동 확인 (예: URL, 텍스트 등)
Playwright 변환 코드
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
page = browser.new_page()
# 1. 로그인 페이지 접속
page.goto("https://example.com")
# 2. 이메일 입력
page.fill("#email", "test@domain.com")
# 3. 비밀번호 입력
page.fill("#pwd", "pw1234")
# 4. 로그인(Confirm) 버튼 클릭
page.click("#formSubmit")
# 5. 로그인 성공 여부(예시: 대시보드 진입)
page.wait_for_load_state("networkidle") # 네트워크 안정화 대기
assert "login_form" not in page.url # URL에 login_form이 없으면 성공으로 간주
browser.close()
결론/추천
- 신규 자동화, 최신 반응형, 복잡한 UI, 모바일/웹킷/사파리 환경 → Playwright 적극 추천
- 기존 셀레니움 코드가 많다면 점진적 병행 사용 또는 점진적 마이그레이션 권장
- 같은 테스트 시나리오를 두 프레임워크로 각각 구현/실행은 가능(코드 재사용은 어려움)
- 비개발자(초보 QA, PM, 운영)도 “CSS selector만 이해하면” 시나리오 → 코드로 직접 구현/수정이 가능
- 필요하면 “실패 검증, 스크린샷, 슬랙 연동, 병렬 실행” 등도 추가 가능
댓글