셀레니움 암시적 대기와 명시적 대기를 같이 쓰면 몇 초 걸릴까?

3줄 요약
- 암시적과 명시적 대기를 섞으면 대기 시간은 어떻게 될까요?
- 암시적 대기가 길면 명시적 5초 제한이 소용없습니다.
- 사라짐을 기다리는 대기는 암시적 값만큼 늘어나니 0으로 내립니다.
같은 코드인데 5.13초, 7.02초, 5.04초, 10.03초, 15.01초가 걸렸습니다. 명시적 대기를 5초로 걸고 요소가 끝내 나오지 않게 만든 페이지에서, 암시적 대기만 0, 2, 5, 10, 15초로 바꿔 가며 잰 값입니다.
셀레니움 공식 문서에는 두 대기를 섞지 말라는 경고가 있습니다. 어디서 얼마나 늘어나는지 궁금해서 직접 재 봤는데요, 시간이 가장 많이 늘어난 곳은 요소가 사라지길 기다리는 대기와 요소가 없음을 확인하는 단언이었습니다. 이 둘이 이 글의 중심입니다.
실험 환경은 Linux 컨테이너의 Python 3.13, selenium 4.51.0, Chromium과 ChromeDriver 141입니다. 페이지는 로컬에 띄운 정적 파일 하나이고, Appium은 문서만 확인했습니다.
암시적 10초에 명시적 5초를 걸면 대기는 10초가 됩니다
요소가 끝내 나오지 않을 때
명시적 대기(WebDriverWait)는 5초로 고정하고 암시적 대기 값만 바꿨습니다. 여러 번 재도 결과는 비슷했습니다. 암시적 10초 조건은 세 번 모두 10.01~10.05초였습니다.
| 암시적 대기 | 명시적 대기 | 걸린 시간 | 결과 |
|---|---|---|---|
| 0초 | 5초 | 5.13초 | TimeoutException |
| 2초 | 5초 | 7.02초 | TimeoutException |
| 5초 | 5초 | 5.04초 | TimeoutException |
| 10초 | 5초 | 10.03초 | TimeoutException |
| 15초 | 5초 | 15.01초 | TimeoutException |
| 3초 | 10초 | 10.10초 | TimeoutException |
| 4초 | 10초 | 13.07초 | TimeoutException |
7.02초가 나와서 WebDriverWait 소스를 열어 봤는데요, 이유가 거기 있었습니다. 명시적 대기는 요소를 찾는 호출을 반복하면서, 호출이 끝날 때마다 제한 시간을 넘었는지 확인합니다. 그런데 암시적 대기가 켜져 있으면 요소가 없을 때 호출 하나가 암시적 시간이 다 지나야 끝납니다.
암시적 4초, 폴링 0.5초라면 호출은 4초, 8.5초, 13초에 끝납니다. 10초 제한을 처음 넘는 시점이 13초라서 13초에 종료되고, 표의 13.07초와 맞습니다. 파이썬 셀레니움은 호출이 끝나면 곧바로 시간을 확인하고, 그다음 폴링 간격(기본 0.5초)만큼 쉽니다. 다른 언어 바인딩은 열어 보지 않았습니다.
요소가 제때 나오면 차이가 없습니다
요소가 3초 뒤에 나타나게 하고 암시적만, 명시적만, 둘 다 걸어 봤습니다. 3.01초, 3.09초, 3.04초였습니다. 요소가 제때 나오면 차이가 없어서 같이 써도 알아채기 어렵습니다. 시간이 늘어나는 곳은 요소가 끝내 안 나오는 경우와 사라짐을 확인하는 경우입니다.
사라지길 기다릴 때 가장 크게 늘어납니다
스피너가 2초 만에 사라졌는데 12초가 걸렸습니다
로딩 스피너가 2초 뒤에 사라지는 페이지에서 invisibility_of_element_located를 20초 제한으로 기다렸습니다. 암시적 대기가 0이면 2.10초, 5초면 7.08초, 10초면 12.10초였습니다. 10초 조건을 다시 재도 12.15초, 12.11초로 비슷했습니다.
스피너가 사라진 뒤의 첫 확인 호출은 "요소가 없다"는 응답을 받으려고 암시적 시간만큼 기다립니다. 그래서 2초면 끝날 일이 암시적 값만큼 더 걸립니다.
없음 단언도 같았습니다
find_elements로 "이 요소가 없다"를 단언하는 경우도 같았습니다. 아래 표는 같은 페이지에서 요소가 없는 상태를 확인하는 데 걸린 시간입니다.
| 확인 대상 | 암시적 0초 | 암시적 5초 | 암시적 10초 |
|---|---|---|---|
없는 요소의 find_elements 단언 |
0.02초 | 5.01초 | 10.04초 |
이미 있는 요소의 find_element |
— | — | 0.02초 |
있는 요소를 찾을 때는 암시적 대기가 10초여도 0.02초였습니다. 암시적 값이 클수록 느려지는 쪽은 없음을 확인하는 단언입니다. 없음 단언이 많은 스위트라면 단언 한 건마다 암시적 값만큼 시간이 더해집니다.
점검 순서
프로젝트에서 암시적 대기를 찾습니다
먼저 코드 어디에 암시적 대기가 있는지 찾습니다. 기본값을 한 곳에서 켜 두는 구성이라면, 그 한 줄이 요소가 없음을 확인하는 모든 곳에 영향을 줍니다. Appium 파이썬 클라이언트도 셀레니움의 implicitly_wait를 그대로 씁니다.
# 암시적 대기 설정 위치를 찾습니다 (파이썬·자바·JS에서 쓰는 이름)
grep -rnE "implicitly_?[wW]ait|implicitWait|setImplicitWait" --include="*.py" --include="*.java" --include="*.js" --include="*.ts" .
값이 0이거나 아예 없으면 이 문제는 해당되지 않거든요. 값이 있다면 테스트 리포트를 느린 순서로 정렬합니다. 그다음 사라짐을 기다리거나 없음을 단언하는 테스트가 위쪽에 있는지 확인합니다.
명시적 대기 동안만 암시적 대기를 0으로 내립니다
암시적 대기를 아예 끄는 것이 가장 단순합니다. 기존 테스트가 암시적 대기에 의존해서 한 번에 끄기 어렵다면, 명시적 대기가 도는 동안만 0으로 내렸다가 되돌리는 헬퍼를 쓰면 됩니다. 아래 코드는 이번 실험에서 쓴 것과 같습니다.
from contextlib import contextmanager
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
@contextmanager
def no_implicit(driver, restore):
"""명시적 대기 동안만 암시적 대기를 0으로 내립니다."""
driver.implicitly_wait(0)
try:
yield
finally:
driver.implicitly_wait(restore) # 원래 값으로 되돌림
def wait_gone(driver, locator, timeout, restore):
with no_implicit(driver, restore):
return WebDriverWait(driver, timeout).until(
EC.invisibility_of_element_located(locator))
이 헬퍼로 같은 스피너 조건(암시적 10초, 2초 뒤 사라짐)을 두 번 돌렸더니 2.09초, 2.09초였습니다. 12초대였던 시간이 2초대로 줄었습니다. find_elements로 하는 없음 단언도 헬퍼 안에서 하면 0.01~0.02초였습니다.
Appium에서는
Appium 문서의 암시적 대기 명령은 단일 요소를 찾을 때 드라이버가 요소를 찾거나 타임아웃이 끝날 때까지 폴링한다고 적고 있습니다. 셀레니움에서 본 구조와 비슷해서 같은 증상이 나올 가능성이 있습니다. Appium 드라이버로는 재 보지 않았으니, Appium 스위트를 쓰는 팀이라면 위 점검을 한 번 돌려 확인해 보십시오.
암시적 대기가 0이 아니라면 사라짐 대기부터 봅니다
암시적 대기가 0이 아니라면 사라짐을 기다리는 부분과 없음을 단언하는 부분부터 의심해 볼 만합니다. 이번 실험에서 12초, 10초로 늘어난 곳도 이 두 곳이었습니다. 다만 표의 숫자는 이 페이지와 이 버전에서 잰 값이라, 팀 환경에서는 다르게 나올 수 있습니다. 그래서 재 보는 것을 권합니다.
재시도와 격리 같은 플래키 대응의 순서는 플래키 테스트 대응 정리에, 시간 제한을 거는 방식은 pytest-timeout 비교에 썼습니다. 대기 시간이 길다 싶으면 제한 시간을 늘리기 전에 암시적 대기와 명시적 대기가 같이 걸려 있는지 먼저 확인하십시오.
댓글
댓글 쓰기