본문 바로가기
Automation

테스트 자동화: Python으로 Appium 서버를 자동으로 실행하기

by codeflow 2024. 4. 10.

Appium 서버를 자동으로 실행시키려면?

파이썬으로 짠 스크립트를 실행시킬 때 appium 서버가 먼저 실행되어 있지 않으면 스크립트가 동작하지 않습니다. appium 서버를 먼저 실행시킬 때 가장 일반적인 방법은 아래와 같이 터미널에서 appium이라는 명령어를 입력하는 것입니다.

그런데 완전한 자동화를 꿈꾼다면 appium 서버를 별도로 실행시키는 게 번거로울 수도 있습니다. 그럴 때는 코드 상에서 appium 서버를 자동으로 실행시키도록 적용하면 되는데요, 파이썬은 pytest의 autouse 기능을 통해 AppiumService fixture가 항상 실행되도록 설정하면 간단하게 해결할 수 있습니다. 아래와 같이 fixture에 autouse=True가 들어가도록 코드를 짜면 됩니다. 해당 코드를 conftest.py 파일에 추가해주면 됩니다.

from appium.webdriver.appium_service import AppiumService

# APPIUM settings
APPIUM_PORT = 4723
APPIUM_HOST = "127.0.0.1"

@pytest.fixture(autouse=True)
def appium_service():
    service = AppiumService()
    service.start(
        args=["--address", APPIUM_HOST, "-p", str(APPIUM_PORT)],
        timeout_ms=20000,
    )
    yield service
    service.stop()

 
appium 서버만 실행시켜서는 테스트 스크립트가 동작하지 않습니다. 모바일 기기를 구동시킬 드라이버도 함께 실행해야 하는데요, android의 경우 desired capabilities를 통해 플랫폼 이름, automation 이름, app 설치 경로만 설정해주면 동작하므로, 이렇게 설정된 최소한의 동작 코드는 다음과 같습니다. 여기서도 driver fixture에 autouse를 True로 설정해주었습니다. 그러면 테스트 함수에서는 별도로 driver fixture를 호출하지 않아도 사용이 가능합니다. 🙂

@pytest.fixture(autouse=True)
def driver():
    driver = create_android_driver()
    yield driver
    driver.quit()


def create_android_driver():
    options = UiAutomator2Options()
    caps = {
        "platformName": "Android",
        "appium:options": {
            "automationName": "UIAutomator2",
            "app": f"{APPS_PATH}/ApiDemos-debug.apk",
        },
    }
    options.load_capabilities(caps)

    return webdriver.Remote(f"http://{APPIUM_HOST}:{APPIUM_PORT}", options=options)

 
이제 appium 서버와 UIAutomator2 드라이버를 실행할 테스트 코드를 짜볼까요? 아주 간단하게 ApiDemos-debug 테스트 앱을 실행시켜서 30초간 화면만 유지하는 코드는 다음과 같습니다. 임의로 test_main.py 파일에 test_sample이라는 테스트 함수를 추가해서 작성했습니다.

import time
def test_sample():
      time.sleep(30)

 
이제 터미널에서 pytest만 입력하면 실행시킬 수 있습니다. 👏👏👏

 
아주 간단한 코드지만 appium 설치 후 테스트 앱을 다운로드 받고, 파이썬 패키지를 설치한 후에 제대로 동작하기 때문에 처음 모바일 테스트 자동화를 시작하시는 분들은 이 설정 부분이 더 어려울 수도 있습니다. 그래서 아래와 같이 정리해두었으니 그대로 따라해보시길 바래요 :)
 

사전 조건

실행 순서

  1. VS Code에서 프로젝트 폴더 생성
  2. 프로젝트 폴더에서 터미널을 열고 python -m venv venv; source venv/bin/activate로 가상환경 설정
  3. 터미널에서 touch requirements.txt, conftest.py, test_main.py 실행해 빈 파일 만들기
  4. 아래 코드 붙여넣기
  5. 터미널에서 pip install -r requirements.txt를 입력해 파이썬 패키지 다운로드
  6. 파인더 혹은 터미널을 통해 테스트 앱을 ~/Downloads/apps 경로에 복사
  7. 터미널에서 pytest를 입력해 appium 서버와 클라이언트 및 테스트 스크립트 실행

프로젝트 트리 구조

.
├── conftest.py
├── requirements.txt
├── test_main.py
└── venv

전체 코드

requirements.txt

Appium-Python-Client>=4.0.0
pytest>=8.1.1

conftest.py

import os
import pytest
from appium import webdriver
from appium.webdriver.appium_service import AppiumService
from appium.options.android import UiAutomator2Options
from appium.options.ios import XCUITestOptions

APPS_PATH = f"{os.path.expanduser('~')}/Downloads/apps"

# APPIUM settings
APPIUM_PORT = 4723
APPIUM_HOST = "127.0.0.1"


@pytest.fixture(scope="session", autouse=True)
def appium_service():
    service = AppiumService()
    service.start(
        args=["--address", APPIUM_HOST, "-p", str(APPIUM_PORT)],
        timeout_ms=20000,
    )
    yield service
    service.stop()


@pytest.fixture(autouse=True)
def driver():
    driver = create_android_driver()
    yield driver
    driver.quit()


def create_android_driver():
    options = UiAutomator2Options()
    caps = {
        "platformName": "Android",
        "appium:options": {
            "automationName": "UIAutomator2",
            "app": f"{APPS_PATH}/ApiDemos-debug.apk",
        },
    }
    options.load_capabilities(caps)

    return webdriver.Remote(f"http://{APPIUM_HOST}:{APPIUM_PORT}", options=options)


def create_ios_driver():
    options = XCUITestOptions()
    caps = {
        "platformName": "iOS",
        "appium:options": {
            "automationName": "XCUITest",
            "app": f"{APPS_PATH}/TestApp.app",
        },
    }
    options.load_capabilities(caps)

    return webdriver.Remote(f"http://{APPIUM_HOST}:{APPIUM_PORT}", options=options)

 

test_main.py

import time
def test_sample():
      time.sleep(30)

댓글