Appium과 Python을 활용한 모바일 화면 스크롤 및 스와이프 제어

모바일 앱 자동화 테스트에서 화면의 스크롤 또는 스와이프 동작은 매우 빈번하게 사용되는 기능입니다. Appium + Python 환경에서는 이러한 제스처를 scroll()swipe() 두 가지 주요 메서드로 구현할 수 있습니다. 각각의 목적과 사용법은 다릅니다.

scroll() 메서드: 요소 간 스크롤 이동

scroll()은 특정 UI 요소에서 다른 요소로 시각적으로 이동하는 동작을 수행합니다. 이는 실제 스크롤바 조작이 아니라, 두 요소의 위치를 기반으로 장치가 자동으로 스크롤을 실행하는 방식입니다.

def scroll_between_elements(self, start_locator, end_locator, duration_ms=None):
    """
    두 웹 요소 사이를 스크롤합니다.
    :param start_locator: 시작 요소의 찾기 전략 (튜플 형식, 예: (By.ID, "id"))
    :param end_locator: 도착 요소의 찾기 전략
    :param duration_ms: 스크롤 지속 시간 (밀리초)
    """
    try:
        source_element = self.wait_for_element(start_locator)
        target_element = self.wait_for_element(end_locator)
        self.driver.scroll(source_element, target_element, duration_ms)
    except Exception as e:
        print(f"스크롤 중 오류 발생: {e}")

여기서 wait_for_element()은 명시적 대기를 적용하여 요소가 나타날 때까지 기다리는 커스텀 메서드입니다. 이를 통해 요소가 로드되지 않아 인식되지 않는 문제를 방지할 수 있습니다.

swipe() 메서드: 좌표 기반 화면 제스처

swipe()은 화면 상의 절대 또는 상대 좌표를 기반으로 드래그 동작을 수행합니다. 따라서 스크롤 거리나 방향을 정밀하게 제어할 수 있습니다.

수직 스와이프 (위/아래)

def swipe_vertical(self, direction='down', duration=1000):
    """
    화면을 수직 방향으로 스와이프합니다.
    :param direction: 'up' 또는 'down'
    :param duration: 제스처 지속 시간 (ms)
    """
    screen_size = self.driver.get_window_size()
    width_center = int(screen_size['width'] * 0.5)
    
    if direction == 'down':
        start_y = int(screen_size['height'] * 0.3)
        end_y = int(screen_size['height'] * 0.7)
    else:  # up
        start_y = int(screen_size['height'] * 0.7)
        end_y = int(screen_size['height'] * 0.3)

    self.driver.swipe(width_center, start_y, width_center, end_y, duration)

수평 스와이프 (좌/우)

def swipe_horizontal(self, direction='left', duration=1000):
    """
    화면을 수평 방향으로 스와이프합니다.
    :param direction: 'left' 또는 'right'
    :param duration: 제스처 지속 시간 (ms)
    """
    screen_size = self.driver.get_window_size()
    height_center = int(screen_size['height'] * 0.5)
    
    if direction == 'left':
        start_x = int(screen_size['width'] * 0.8)
        end_x = int(screen_size['width'] * 0.2)
    else:  # right
        start_x = int(screen_size['width'] * 0.2)
        end_x = int(screen_size['width'] * 0.8)

    self.driver.swipe(start_x, height_center, end_x, height_center, duration)

특정 UI 요소 내에서 스와이프

전체 화면이 아닌 특정 뷰(예: 리스트뷰, 리사이클러뷰) 내부에서만 스와이프를 수행해야 할 경우도 있습니다. 아래 메서드는 요소의 경계 내에서 상대 좌표를 계산하여 제스처를 적용합니다.

def swipe_within_element(self, locator, swipe_type='down', duration=1000):
    """
    특정 요소 내부에서 스와이프 동작을 수행합니다.
    :param locator: 대상 요소의 위치자
    :param swipe_type: 'up', 'down', 'left', 'right'
    :param duration: 제스처 지속 시간
    """
    element = self.wait_for_element(locator)
    location = element.location
    size = element.size

    center_x = location['x'] + size['width'] // 2
    center_y = location['y'] + size['height'] // 2

    if swipe_type == 'down':
        start_y = int(location['y'] + size['height'] * 0.4)
        end_y = int(location['y'] + size['height'] * 0.6)
        self.driver.swipe(center_x, start_y, center_x, end_y, duration)
    elif swipe_type == 'up':
        start_y = int(location['y'] + size['height'] * 0.6)
        end_y = int(location['y'] + size['height'] * 0.4)
        self.driver.swipe(center_x, start_y, center_x, end_y, duration)

scroll() vs swipe(): 핵심 차이점

  • scroll(): 요소 기반. 애플리케이션의 UI 계층 구조를 이해하고 있으며, 두 요소 사이를 자연스럽게 스크롤합니다. 하지만 스크롤 거리 조절이 불가능하며, 요소가 반드시 존재해야 합니다.
  • swipe(): 좌표 기반. 물리적인 제스처를 시뮬레이션하므로 더 많은 제어가 가능하지만, 해상도나 디바이스 크기에 따라 동작이 달라질 수 있어 상대 좌표 비율 사용이 권장됩니다.

따라서 일반적인 탐색에는 scroll()을, 정밀한 제어나 커스텀 뷰 제어에는 swipe()을 사용하는 것이 적절합니다.

태그: Appium python Mobile Automation Swipe Scroll

6월 30일 16:40에 게시됨