Selenium으로 E2E 테스트 자동화를 운용하고 있는 QA 엔지니어가 실제로 경험한 「운용 붕괴」 실패담을 7선으로 해설합니다. ChromeDriver 버전 관리·Wait 혼재·xpath 셀렉터 의존·특정인 의존 등, Selenium 고유의 「작동하다가 무너지는」 패턴과 복구 방법을 실무 경험을 바탕으로 소개합니다. 참고로 「유지보수 부채」란 수정 비용이 눈덩이처럼 불어나는 상태를 말합니다.
「처음에는 잘 작동했는데, 어느새 아무도 건드릴 수 없는 코드가 됐다」——Selenium 운용 붕괴는 갑자기 일어나는 것이 아니라, 서서히 진행됩니다.
📌 이런 분께 추천합니다
- Selenium E2E 테스트를 운용하고 있지만 왠지 불안정해지고 있다고 느끼는 분
- 「왜 갑자기 테스트가 실패하지?」「유지보수가 따라가지 못한다」고 느끼는 QA 엔지니어
- Selenium 운용의 건전화·복구를 검토하고 있는 테스트 리드
- Selenium에서 Playwright로의 이전 판단 근거가 필요한 분
✅ 이 기사를 읽으면 얻을 수 있는 것
- Selenium 고유의 운용 붕괴 패턴 7가지와 구체적인 붕괴 과정을 알 수 있다
- 「아직 붕괴되지 않았지만 예조가 있다」상태를 조기에 발견하는 방법을 알 수 있다
- 각 패턴의 복구 방법·예방책을 알 수 있다
👤 이 기사를 쓴 사람
QA 엔지니어·테스트 자동화 엔지니어로서 15년 이상의 실무 경험을 가진 Yoshi가 집필. Selenium을 사용한 자동화의 구축부터 운용이 붕괴되는 과정, 그리고 복구까지를 여러 프로젝트에서 경험했습니다.
📖 관련 기사와의 사용 구분
- 테스트 자동화에서 자주 발생하는 실패 5선:도구 비의존의 「전략·설계」레벨의 실패 → 「무엇을 자동화해야 하는가」판단에서 실패한 분은 이쪽
- Playwright 도입에서 실패한 이야기 7선:Playwright 고유의 도입 실수 → Playwright로 이전 후 실패한 분은 이쪽
- 이 기사:Selenium 고유의 「운용 계속 중에 서서히 붕괴되는 패턴」
📌 결론 (3가지 포인트)
- Selenium 운용 붕괴는 「ChromeDriver 관리」「Wait 설계」「셀렉터 설계」라는 Selenium 고유의 3가지 지뢰에서 시작된다
- 붕괴는 갑자기 일어나지 않으며, 「왠지 불안정하다」「수정이 따라가지 못한다」는 예조가 있다. 예조 단계에서 대처할 수 있다
- Selenium이 나쁜 것이 아니다. 운용 설계 없이 확대한 것이 붕괴의 본질이다
「처음 반년은 순조로웠다. 하지만 1년 후, 아무도 그 테스트 코드를 건드리지 않게 됐다」——여러 프로젝트에서 반복해서 목격해 온 광경입니다.
Selenium 운용 악화에 공통되는 것은, 「갑자기 무너지는」것이 아니라 「서서히 무너져 간다」는 것입니다. 이 기사에서는 유지보수 부채의 7가지 패턴과 각각의 복구 방법을 실체험을 바탕으로 해설합니다.
🔍 먼저 확인:당신의 Selenium 운용 예조 체크
- CI가 주 1회 이상 ChromeDriver 원인으로 실패한다
- 코드 내에
implicitly_wait와WebDriverWait가 설계 방침 없이 혼재하고 있다 - xpath의 풀 패스나 class 의존 셀렉터가 대량으로 있다
- 같은 로그인 처리가 여러 곳에 복사&붙여넣기 되어 있다
- 「이 테스트는 XX씨에게 물어봐야 알 수 있다」는 상황이 있다
- 로컬에서는 작동하지만 CI(헤드리스)에서는 실패하는 테스트가 있다
requirements.txt에서 버전을 고정하지 않았다
| ✅ 0〜2개:건전 계속 정기적으로 확인을 | ⚠️ 3〜4개:주의 해당 항목부터 우선 대처 | 🚨 5개 이상:위험 지금 당장 복구 계획을 |
- Selenium 운용 붕괴 이야기 7선이란?조견표
- ① ChromeDriver 버전 관리 지옥이란?
- ② implicitWait와 explicitWait를 혼재시켜 Flaky 지옥이 됐다란?
- ③ xpath 셀렉터 의존으로 UI 리뉴얼마다 전체 붕괴란?
- ④ Page Object화하지 않고 1000행 스크립트가 탄생했다란?
- ⑤ 담당자가 퇴직하여 아무도 건드릴 수 없는 코드가 됐다란?
- ⑥ 헤드리스화 못 해 CI에 편입할 수 없었다란?
- ⑦ Selenium 4 업그레이드로 전체 테스트가 작동하지 않게 됐다란?
- Selenium을 계속하는 것이 좋은 케이스란?
- FAQ
Selenium 운용 붕괴 이야기 7선이란?조견표
| # | 패턴 | 근본 원인 | CI 영향 | 수정 비용 |
|---|---|---|---|---|
| ① | ChromeDriver 버전 관리 지옥 | 바이너리 관리 구조 없음 | 🔴 높음 | 🟢 낮음 |
| ② | implicitWait·explicitWait 혼재 | Wait 설계 사상의 불통일 | 🔴 높음 | 🟡 중간 |
| ③ | xpath 셀렉터 의존 | 취약한 셀렉터 설계 | 🔴 높음 | 🔴 높음 |
| ④ | 1000행 스크립트의 비대화 | 설계 없는 「작동하면 된다」개발 | 🟡 중간 | 🔴 높음 |
| ⑤ | 담당자 퇴직으로 아무도 건드릴 수 없는 코드 | 특정인 의존한 채로 운용 확대 | 🟡 중간 | 🔴 높음 |
| ⑥ | 헤드리스화 못해 CI 편입 불가 | 로컬 전제의 구현 설계 | 🔴 높음 | 🟡 중간 |
| ⑦ | Selenium 4 업그레이드로 전체 테스트 정지 | 의존성 관리·이전 계획 부재 | 🔴 높음 | 🟡 중간 |
① ChromeDriver 버전 관리 지옥이란?
무슨 일이 일어났나
월요일 아침, CI가 갑자기 실패합니다. 로그를 보면 SessionNotCreatedException: This version of ChromeDriver only supports Chrome version XX. 주말 사이 Chrome이 자동 업데이트되어 ChromeDriver와 버전이 맞지 않아진 것입니다.
처음에는 「ChromeDriver를 다운로드해서 교체하면 된다」고 생각했습니다. 하지만 이것이 매주 반복됩니다. 다운로드 페이지를 찾고→버전을 확인하고→교체하고→CI를 재실행하고——이 작업에 매주 월요일 오전이 사라졌습니다.
붕괴의 예조
- ChromeDriver의 경로가 하드코딩되어 있다
requirements.txt에 ChromeDriver 버전이 기재되어 있지 않다- CI 환경의 Chrome 버전 관리가 「대략 최신」으로 되어 있다
- ChromeDriver 다운로드가 수동 작업이 되어 있다
# ❌ 붕괴 패턴:ChromeDriver 경로를 하드코딩
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
driver = webdriver.Chrome(service=Service("/usr/local/bin/chromedriver"))
# 버전이 맞지 않으면 매번 여기서 에러가 난다
# ✅ 선택지①:Selenium 4.6+ 의 Selenium Manager(표준 탑재)
# Selenium 4.6 이후는 ChromeDriver 자동 관리가 표준 기능으로 탑재
# 단, CI·Docker 환경에서는 OS 의존 등으로 추가 조정이 필요한 경우가 있다
from selenium import webdriver
driver = webdriver.Chrome()
# 추가 라이브러리 불필요(단, 환경 의존의 조정이 필요한 케이스 있음)
# ✅ 선택지②:webdriver-manager(기존 프로젝트·CI 환경에서 널리 이용)
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
driver = webdriver.Chrome(
service=Service(ChromeDriverManager().install())
)
# 기존 환경이나 Selenium 4.6 미만에서도 계속 유효- Chrome이 설치되어 있지 않음:최소 구성의 Docker 이미지에는 Chrome 자체가 없다
- PATH 문제:컨테이너 환경에서 Chrome/ChromeDriver의 경로가 통하지 않는다
- 권한 제한:바이너리 취득이 파일시스템 제한으로 블록된다
기존 프로젝트나 CI 환경에서는 webdriver-manager가 계속 널리 사용되고 있으므로, 팀 운용에 맞게 선택하세요. CI에서는 Docker 이미지의 Chrome 버전을 고정하는 방법도 병용하면 더 안정됩니다.
② implicitWait와 explicitWait를 혼재시켜 Flaky 지옥이 됐다란?
※ Flaky 테스트란 「성공하기도 하고 실패하기도 하는 불안정하고 재현성 없는 테스트」를 말합니다. CI를 실행할 때마다 결과가 바뀌기 때문에 「실제 버그인지 불안정한 것인지」판단이 어려워집니다.
무슨 일이 일어났나
「대기 처리를 제대로 하자」고 문서를 읽은 결과, implicitly_wait와 WebDriverWait를 모두 코드 내에 혼재시켜버렸습니다. 작동하는 날도 있고 실패하는 날도 있는——재현성 없는 Flaky 테스트가 대량 발생하여, 「테스트가 실패해도 실제 버그인지 알 수 없는」상태가 됐습니다.
implicitly_wait는 드라이버 전체에 설정되는 글로벌 대기. 한 번 설정하면 세션 전체에 영향WebDriverWait는 특정 요소를 대상으로 한 명시적 대기- 혼재하면 타임아웃 예측이 어려워지고, 테스트마다 대기 동작이 제각각이 되어 디버깅이 곤란해진다. Selenium 공식도 혼재를 피하도록 권장하고 있다
- 단기적으로 안정되는 케이스도 있지만, 테스트 수가 늘수록 이 리스크가 현재화됩니다. 기본 방침은 explicitWait로 통일하는 것이 추천됩니다
참고:Flaky의 원인은 Wait 설계만이 아닙니다. 네트워크 지연·렌더링 차이·테스트 간 상태 공유도 주요 원인이 됩니다. Wait 설계 정리는 「Flaky를 유발하는 요소 중 하나를 없애는」 작업입니다.
# ❌ 붕괴 패턴:implicitWait와 explicitWait의 혼재
driver.implicitly_wait(10) # 글로벌 설정
# 다른 곳에서
wait = WebDriverWait(driver, 5)
element = wait.until(EC.presence_of_element_located((By.ID, "submit")))
# 타임아웃 계산이 간섭하여 Flaky의 원인이 된다
# ✅ 복구 방법:explicitWait로 통일한다
# implicitly_wait 는 사용하지 않는다
# 모든 것을 WebDriverWait로 명시적으로 대기
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
wait = WebDriverWait(driver, 10)
element = wait.until(
EC.element_to_be_clickable((By.ID, "submit"))
)
element.click()implicitly_wait가 혼재하고 있다면, 먼저 그것을 모두 제거하는 것부터 시작합니다. grep -r "implicitly_wait" ./tests로 전체 건수를 확인하세요.③ xpath 셀렉터 의존으로 UI 리뉴얼마다 전체 붕괴란?
무슨 일이 일어났나
「어쨌든 요소를 지정할 수 있으면 된다」는 방침으로, xpath를 풀 패스로 지정한 테스트 코드가 축적됐습니다. 6개월 후, 프론트엔드 리뉴얼로 HTML 구조가 바뀌었을 때, 300건의 테스트 중 280건이 동시에 실패했습니다. xpath의 경로가 무효가 된 것입니다.
# ❌ 붕괴 패턴:풀 패스 xpath 의존
driver.find_element(
By.XPATH,
"/html/body/div[2]/main/section[1]/form/div[3]/button"
)
# HTML 구조가 조금만 바뀌어도 전체 붕괴
# ⚠️ 상대 xpath도 취약한 경우가 있다
driver.find_element(By.XPATH, "//div[@class='btn-wrapper']/button[1]")
# class가 바뀌면 깨진다
# ✅ 권장:data-testid를 사용한 CSS Selector가 가장 안정적
driver.find_element(By.CSS_SELECTOR, "[data-testid='submit-btn']")
# data-testid는 테스트 전용 속성 → UI 리뉴얼에서도 바꾸지 않는 규칙을 만들 수 있다
# ✅ 차선:ID나 name 속성
driver.find_element(By.ID, "submit-btn")
driver.find_element(By.NAME, "submit")셀렉터 안정성 비교
| 셀렉터 종류 | UI 변경 내성 | 권장도 |
|---|---|---|
data-testid 속성 | ✅ 최강 | 개발 팀과 합의하여 필수화 |
| ID 속성 | ✅ 강함 | ID가 있는 요소에서는 적극 사용 |
| name/aria-label 속성 | △ 중간 | 있는 경우는 적극 활용 |
| 안정 속성 CSS/XPath 예: //button[@type='submit'] | △〜○ 조건부 | aria 속성·type 속성 등 변하기 어려운 속성을 사용하면 실용적 |
| class 의존 CSS/XPath | ⚠️ 약함 | 디자인 변경에 깨지기 쉬움. 최후의 수단 |
| xpath(풀 패스) | ❌ 매우 낮음 | 기본적으로 피한다(변경 빈도가 낮은 관리 화면 등 한정적 용도에서는 예외적으로 사용되는 경우도 있다) |
data-testid 속성 부여를 표준화해달라고 요청하는 것이 가장 근본적인 해결책입니다. 기존 xpath는 grep -r "By.XPATH" ./tests로 찾아내어 우선도가 높은 테스트부터 순차적으로 교체합니다.④ Page Object화하지 않고 1000행 스크립트가 탄생했다란?
무슨 일이 일어났나
「우선 작동시키는 것이 우선」이라는 방침으로 테스트를 계속 추가한 결과, 하나의 테스트 파일이 1000행을 초과했습니다. 로그인 처리가 5곳에 복사&붙여넣기 되어 있어, 로그인 화면의 셀렉터가 바뀌면 5곳 모두를 수정해야 합니다. 수정 누락으로 버그가 숨어들게 됐습니다.
# ❌ 붕괴 패턴:같은 조작이 코드 내에 분산
def test_purchase():
driver.find_element(By.ID, "email").send_keys("user@example.com")
driver.find_element(By.ID, "password").send_keys("pass")
driver.find_element(By.ID, "login-btn").click()
# ...구매 처리...
def test_profile():
driver.find_element(By.ID, "email").send_keys("user@example.com") # 중복
driver.find_element(By.ID, "password").send_keys("pass") # 중복
driver.find_element(By.ID, "login-btn").click() # 중복
# ...프로필 처리...
# ✅ 복구 방법:Page Object Model로 조작을 집약
class LoginPage:
def __init__(self, driver):
self.driver = driver
def login(self, email: str, password: str):
self.driver.find_element(By.ID, "email").send_keys(email)
self.driver.find_element(By.ID, "password").send_keys(password)
self.driver.find_element(By.ID, "login-btn").click()
# 테스트 코드는 의도만 작성한다
def test_purchase(driver):
LoginPage(driver).login("user@example.com", "pass")
# ...구매 처리만...- UI 변경 빈도:변경이 많은 화면일수록 집약 가치가 높다(변경 부분을 1곳에 모을 수 있다)
- 테스트의 재이용성:여러 테스트 시나리오에서 호출되는 조작은 우선적으로 Page Object화한다
- 도메인의 경계:「로그인」「상품 검색」「장바구니 조작」등, 기능 단위로 분리하면 유지보수가 쉬워진다
1000행이 된 후에 고치는 것은 대공사이지만, 300행 단계라면 비교적 원활하게 정리할 수 있습니다.
⑤ 담당자가 퇴직하여 아무도 건드릴 수 없는 코드가 됐다란?
무슨 일이 일어났나
「이 Selenium 테스트는 A씨밖에 모른다」——A씨가 퇴직한 다음 달, 테스트가 실패해도 아무도 고칠 수 없는 상태가 됐습니다. 코드에 주석은 없고, 로컬 환경 구축 순서도 문서화되어 있지 않았습니다. 「테스트가 실패해도 방치한다」는 문화가 생겨나 자동화가 형식화되어 갔습니다.
특정인 의존의 구체적인 증상 체크리스트
※ Yes/No만이 아니라 「팀의 몇 퍼센트가 대응할 수 있는가」라는 관점으로도 확인해 보세요. 1명만 대응할 수 있는 상태가 특정인 의존의 본질입니다.
| 체크 항목 | 당신의 팀은? |
|---|---|
| README만으로 환경 구축이 완료된다 | ✅ / ❌ |
| 담당자 이외의 사람이 테스트를 추가·수정할 수 있다 | ✅ / ❌ |
| 테스트 코드의 코드 리뷰가 이루어지고 있다 | ✅ / ❌ |
| 테스트가 실패했을 때 여러 사람이 원인을 조사할 수 있다 | ✅ / ❌ |
| 「이 테스트는 XX씨에게 물어봐야 알 수 있다」가 없다 | ✅ / ❌ |
⑥ 헤드리스화 못 해 CI에 편입할 수 없었다란?
무슨 일이 일어났나
「로컬에서는 작동한다」지만, CI 서버(헤드리스 환경)에서 실행하면 일제히 에러가 납니다. 조사해 보니, 브라우저의 윈도우 크기와 화면 렌더링에 의존한 조작이 테스트 내에 분산되어 있는 것이 판명났습니다. 구체적으로는 다음과 같은 문제들이 얽혀 있었습니다.
- viewport 크기 차이:로컬은 1920×1080, 헤드리스 기본값은 800×600 등 — 요소가 viewport 밖으로 나와 클릭 불가
- lazy rendering:스크롤할 때까지 렌더링되지 않는 요소(지연 로딩)가 헤드리스에서 미렌더링인 채로
- sticky / fixed UI:헤더나 사이드바가 fixed로 요소에 겹쳐 클릭이 블록된다
- responsive breakpoint:화면 폭이 바뀌면 레이아웃이 무너져 예상 요소가 표시되지 않게 된다
# ❌ 붕괴 패턴:헤드리스에서 작동하지 않는 구현
# 화면 크기를 전제로 한 스크롤 조작
driver.execute_script("window.scrollTo(0, 500)")
driver.find_element(By.ID, "submit").click()
# 헤드리스에서는 500px 위치에 요소가 없을 수 있다
# ❌ viewport 밖 요소를 클릭(헤드리스에서 실패)
element = driver.find_element(By.ID, "footer-btn")
element.click() # 화면 밖일 경우 에러
# ✅ 복구 방법①:스크롤하고 나서 조작
element = driver.find_element(By.ID, "submit")
driver.execute_script("arguments[0].scrollIntoView(true);", element)
element.click()
# ✅ 복구 방법②:윈도우 크기를 명시적으로 설정
from selenium import webdriver
options = webdriver.ChromeOptions()
options.add_argument("--headless")
options.add_argument("--window-size=1920,1080") # CI 환경에서 크기를 고정
driver = webdriver.Chrome(options=options)--window-size=1920,1080를 항상 옵션에 넣고, scrollIntoView를 사용한 조작을 표준화하면 헤드리스 차이에 의한 에러가 크게 줄어듭니다. 단 fixed/sticky 헤더가 요소에 겹치는 경우는 scrollIntoView만으로는 ElementClickInterceptedException이 발생하는 경우가 있습니다. 그럴 때는 JavaScript의 arguments[0].click()으로 직접 클릭하거나 헤더 높이만큼 오프셋을 조정하는 대처가 필요합니다.⑦ Selenium 4 업그레이드로 전체 테스트가 작동하지 않게 됐다란?
무슨 일이 일어났나
pip install selenium --upgrade로 Selenium 3에서 4로 버전을 올린 직후, 다음날 CI에서 200건의 테스트 중 150건 이상이 한꺼번에 실패했습니다. Selenium 4에서 폐지된 API가 여러 개 있는데, 이전 계획 없는 업그레이드가 대참사를 일으켰습니다.
Selenium 3→4에서 폐지·변경된 주요 API
| Selenium 3 작성법 | Selenium 4에서의 변경 |
|---|---|
driver.find_element_by_id("x") | driver.find_element(By.ID, "x")로 통일 |
driver.find_element_by_xpath("//x") | driver.find_element(By.XPATH, "//x") |
webdriver.Chrome(executable_path="...") | Service 객체 경유가 권장됨 |
DesiredCapabilities | Options 클래스에 통합 |
requirements.txt에서 버전을 고정하지 않은 것이 이번 붕괴의 직접 원인이었습니다.# ❌ 붕괴 패턴:Selenium 3의 폐지 API를 계속 사용
driver.find_element_by_id("submit") # Selenium 4에서 삭제
driver.find_element_by_xpath("//button") # Selenium 4에서 삭제
driver.find_element_by_class_name("btn") # Selenium 4에서 삭제
# ✅ Selenium 4 대응 작성법(By.XXX 사용)
from selenium.webdriver.common.by import By
driver.find_element(By.ID, "submit")
driver.find_element(By.XPATH, "//button")
driver.find_element(By.CLASS_NAME, "btn")grep -r "find_element_by_" ./tests로 구 API 사용 부분을 찾아냅니다. sed로 일괄 치환도 가능합니다. 향후에는 requirements.txt에 버전을 고정하고, 업그레이드는 전용 브랜치에서 계획적으로 진행하세요.Selenium을 계속하는 것이 좋은 케이스란?
이 기사에서는 운용상의 문제점을 중심으로 해설했지만, 모든 현장에서 Playwright 이전이 정답은 아닙니다. 다음과 같은 경우에는 Selenium을 계속하는 것이 보다 현실적인 선택입니다.
Selenium 계속이 현실적인 케이스
- Selenium Grid 자산이 대규모:병렬 실행 인프라가 성숙하여 이전 비용이 막대한 경우
- Java·C# 기반의 자동화 기반:Python이나 TypeScript로의 이전이 현실적이지 않은 팀 문화
- IE·레거시 브라우저 대응이 필요:Playwright는 IE를 지원하지 않는다
- 기존의 수천 건 규모의 Selenium이 안정 운용 중:작동하는 것을 망가뜨리는 리스크가 이전 메리트를 상회하는 경우
판단에 사용할 수 있는 2가지 축
- 팀 스킬:TypeScript·JS 문화가 없는 팀에서 Playwright를 도입하면, 특정인 의존이 그대로 이식된다
- CI 성숙도:CI가 정비되지 않은 단계에서의 도구 이전은 이전 비용을 올바르게 견적하지 못해 중도에 멈추기 쉽다
FAQ
Q. Selenium은 Playwright로 대체되어 가고 있나요?
Selenium은 「구식」이 아닙니다. 2024〜2025년에도 Selenium 4 계열의 업데이트가 계속되고 있으며, Selenium Manager 등의 새 기능도 추가되고 있습니다. 구인 시장에서도 Selenium의 수요는 여전히 높은 상태가 계속되고 있습니다. 다만 신규 프로젝트에서 Playwright를 채용하는 케이스는 증가하고 있으며, 양자의 강점 영역에서 구분하여 사용하는 것이 현실적입니다. 「어느 쪽이 절대적으로 우수하다」는 것이 아니라, 팀의 기술 스택·기존 자산·프로젝트 요건으로 판단하는 것이 베스트입니다.
Q. Selenium의 유지보수 부채를 막기 위해 가장 먼저 해야 할 것은 무엇인가요?
우선도 순서로 3가지입니다. ①requirements.txt에서 버전을 고정한다(오늘 할 수 있다·효과가 크다·리스크 제로), ②Selenium 4.6+의 Selenium Manager 또는 webdriver-manager로 ChromeDriver 관리를 자동화한다(1일 완료), ③implicitly_wait 사용 부분을 grep으로 찾아 제거한다(1〜2일). 이 3가지만으로도 부채 리스크가 크게 줄어듭니다.
Q. 維持不能이 된 Selenium 테스트 스위트를 전부 재작성해야 하나요?
한꺼번에 전부 재작성하는 것은 높은 리스크입니다. 「가장 자주 실행되는 테스트 상위 20건」부터 우선적으로 정리하는 접근법이 현실적입니다. 전체 재작성보다 「작동하는 테스트를 망가뜨리지 않고 개선해 간다」방침 쪽이 비즈니스적 리스크가 낮아집니다.
Q. Selenium에서 Playwright로의 이전을 검토해야 할 타이밍은 언제인가요?
먼저 보충으로:Selenium 4.6 이후에는 Selenium Manager로 ChromeDriver 관리 문제의 대부분은 개선됩니다. 이전 판단의 본질적인 기준은 「현재 유지보수 부채 해소 비용」과 「이전 비용」 중 어느 쪽이 큰가입니다. 「Flaky가 너무 많아 CI에 대한 신뢰를 잃었다」「테스트를 추가할 때마다 부채가 쌓인다」는 과제도 Selenium인 채로 설계 개선으로 해소되는 경우가 있습니다. 이전 전에 테스트 설계 문제를 정리하지 않으면, 같은 문제가 Playwright에서도 재발합니다.
📖 관련 기사(이 기사와 합쳐서 읽으면 이해가 깊어집니다)
【Selenium 구현】
- Selenium + Python + pytest 환경 구축|webdriver-manager로 자동 관리
- Selenium × pytest 실전 가이드|fixture·parametrize·conftest.py·mark
【설계·이전 판단】
- Page Object Model이란?유지보수 비용 폭발을 막는 설계 패턴
- Playwright 도입에서 실패한 이야기 7선|Selenium 이전의 함정
- 테스트 자동화에서 자주 발생하는 실패 5선|전략·설계 레벨의 실패와 개선책
- 자동화하지 않는 것이 좋은 테스트 케이스 7선
【로드맵】
🚀 지금 당장 시작하는 우선순위 TOP3
읽은 당일에 실시할 수 있는 대처부터 시작하세요.
| 1위 | requirements.txt에서 버전을 고정한다 오늘 할 수 있다·효과가 크다·리스크 제로 |
| 2위 | implicitly_wait 사용 부분을 grep으로 찾아낸다grep -r "implicitly_wait" ./tests로 전체 건수 확인·1〜2일로 대처 가능 |
| 3위 | xpath 풀 패스 사용 부분을 grep으로 찾아낸다grep -r "By.XPATH" ./tests로 확인하여 영향도가 높은 것부터 data-testid화를 진행한다 |
Selenium은 20년 이상의 역사를 가진 실적 있는 도구입니다. 이 기사에서 소개한 7가지 패턴은 모두 「Selenium이 나쁘다」는 것이 아니라 「운용 설계 없이 확대한 결과」였습니다. 오늘부터라도 예조를 확인하고, 하나씩 대처해 나가면 유지 불가능해진 운용도 반드시 복구할 수 있습니다.
📋 이 기사의 정리
- ChromeDriver 버전 불일치는 Selenium 4.6+ Selenium Manager 또는 webdriver-manager로 자동 관리 가능—환경에 맞게 선택
- implicitWait와 explicitWait 혼재는 타임아웃 동작을 예측 불가능하게 만든다. explicitWait로 통일하는 것이 기본
- xpath 풀 패스는 기본적으로 피한다. 안정 속성 CSS/XPath·data-testid로 이행을 진행한다
- Page Object화의 기준:중복 빈도·UI 변경 빈도·도메인 경계 — 「2곳 이상」만이 아니다
- 특정인 의존 해소는 README 정비와 테스트 코드에 코드 리뷰 적용부터 시작한다
- 헤드리스 차이(viewport·lazy render·sticky UI)는 로컬에서 확인 가능. window-size 고정과 scrollIntoView를 표준화하고, JS 클릭이 필요한 경우를 파악한다
- 메이저 버전 업그레이드는 전용 브랜치에서 계획적으로. requirements.txt 버전 고정은 필수
- Selenium을 계속해야 하는 케이스도 있다. 「유행이니까」가 아니라 현재 과제에 최적인지로 판단한다
