Appium Python PO模式实践指南

项目结构

project/
├── config/                  # 配置文件
│   └── device_config.py     # 设备配置参数
├── pages/                   # 页面对象模型(Page Object)
│   └── home_page.py         # 首页操作封装
├── tests/                   # 测试用例
│   └── test_ui_actions.py   # UI 操作测试
├── utils/                   # 工具类
│   ├── driver.py            # 驱动管理
│   └── adb_utils.py         # ADB 命令封装(如关机、重启)
└── conftest.py              # pytest 全局配置

1. 配置文件 config/device_config.py

# Android 设备配置
ANDROID_CAPS = {
    "platformName": "Android",
    "appium:deviceName": "Pixel_4_API_30",  # 设备名称(adb devices 查看)
    "appium:platformVersion": "11.0",       # 系统版本
    "appium:appPackage": "com.android.settings",  # 测试的 App 包名(示例为系统设置)
    "appium:appActivity": ".Settings",             # App 的主 Activity
    "appium:automationName": "UiAutomator2",       # Android 驱动引擎
    "appium:noReset": True,                        # 不重置 App 状态
    "appium:udid": "emulator-5554"                 # 设备唯一标识
}

APPIUM_SERVER = "http://localhost:4723/wd/hub"     # Appium 服务地址

2. 驱动管理 utils/driver.py

from appium import webdriver
from config.device_config import APPIUM_SERVER, ANDROID_CAPS

def init_driver():
    """初始化 Appium 驱动"""
    driver = webdriver.Remote(
        command_executor=APPIUM_SERVER,
        desired_capabilities=ANDROID_CAPS
    )
    return driver

def quit_driver(driver):
    """关闭驱动"""
    if driver:
        driver.quit()

3. 页面操作封装 pages/home_page.py

from appium.webdriver.common.appiumby import AppiumBy

class HomePage:
    def __init__(self, driver):
        self.driver = driver

    # ------------------- 点击操作 -------------------
    def click_element_by_id(self, element_id):
        """通过 ID 点击元素"""
        self.driver.find_element(AppiumBy.ID, element_id).click()

    def click_element_by_text(self, text):
        """通过文本点击元素(XPath 定位)"""
        xpath = f"//*[@text='{text}']"
        self.driver.find_element(AppiumBy.XPATH, xpath).click()

    # ------------------- 滑动操作 -------------------
    def swipe_up(self, duration=1000):
        """向上滑动屏幕"""
        window_size = self.driver.get_window_size()
        start_x = window_size["width"] * 0.5
        start_y = window_size["height"] * 0.8
        end_y = window_size["height"] * 0.2
        self.driver.swipe(start_x, start_y, start_x, end_y, duration)

    def swipe_to_element(self, element_id, max_swipes=5):
        """滑动直到找到元素"""
        for _ in range(max_swipes):
            try:
                element = self.driver.find_element(AppiumBy.ID, element_id)
                return element
            except:
                self.swipe_up()
        raise Exception(f"Element {element_id} not found after {max_swipes} swipes")

    # ------------------- 输入操作 -------------------
    def input_text(self, element_id, text):
        """向输入框输入文本"""
        element = self.driver.find_element(AppiumBy.ID, element_id)
        element.clear()
        element.send_keys(text)

4. 设备操作工具 utils/adb_utils.py

import subprocess

class ADBUtils:
    def __init__(self, device_id="emulator-5554"):
        self.device_id = device_id

    def execute_adb_command(self, command):
        """执行 ADB 命令"""
        cmd = f"adb -s {self.device_id} {command}"
        subprocess.run(cmd, shell=True, check=True)

    def reboot_device(self):
        """重启设备"""
        self.execute_adb_command("reboot")

    def power_off(self):
        """关闭设备(需 root 权限)"""
        self.execute_adb_command("shell reboot -p")

    def unlock_screen(self):
        """解锁屏幕"""
        self.execute_adb_command("shell input keyevent 82")  # KEYCODE_MENU

5. 测试用例 tests/test_ui_actions.py

import pytest
from utils.driver import init_driver, quit_driver
from pages.home_page import HomePage
from utils.adb_utils import ADBUtils

@pytest.fixture(scope="function")
def driver():
    driver = init_driver()
    yield driver
    quit_driver(driver)

def test_click_and_swipe(driver):
    home_page = HomePage(driver)
    # 点击进入“网络和互联网”设置
    home_page.click_element_by_text("网络和互联网")
    # 滑动查找“热点”选项
    home_page.swipe_to_element("com.android.settings:id/title")

def test_input_text(driver):
    home_page = HomePage(driver)
    # 进入“系统”设置
    home_page.click_element_by_text("系统")
    # 进入“关于手机”
    home_page.click_element_by_text("关于手机")
    # 输入设备名称
    home_page.input_text("com.android.settings:id/device_name", "My Phone")

def test_reboot_device(driver):
    adb = ADBUtils()
    adb.reboot_device()
    # 等待设备重启后重新连接
    driver = init_driver()
    assert driver.is_app_installed("com.android.settings")

6. 全局配置 conftest.py

import pytest
from utils.driver import init_driver, quit_driver

@pytest.fixture(scope="session", autouse=True)
def appium_server():
    """启动 Appium 服务(可选,或手动启动)"""
    # 这里可以添加启动 Appium 的代码,但通常建议手动启动
    yield
    # 清理操作

关键操作详解

1. 点击操作
  • 通过 ID 点击:直接使用 find_element(AppiumBy.ID, "element_id").click()

  • 通过文本点击:使用 XPath 定位,如 //*[@text='确定']

  • 2. 滑动操作
  • 坐标滑动driver.swipe(start_x, start_y, end_x, end_y, duration)

  • 滑动到元素:结合循环和 swipe,直到找到目标元素。

  • 3. 设备控制
  • 重启/关机:通过 adb 命令实现(需设备权限)。

  • 解锁屏幕:发送 ADB 按键事件(如 input keyevent 82)。

  • 4. 输入文本
  • 先清空输入框:element.clear()

  • 输入内容:element.send_keys("text")


  • 运行测试

    # 启动 Appium 服务
    appium
    
    # 运行测试
    pytest tests/test_ui_actions.py -v

    最佳实践

    1. 使用 Page Object 模式:将页面元素和操作封装到 pages 目录。

    2. 分离配置和代码:设备参数放在 config 中,便于多环境切换。

    3. ADB 与 Appium 结合:复杂设备操作(如重启)用 ADB,UI 操作用 Appium。

    4. 异常处理:在滑动、查找元素时添加重试机制。

    作者:白白胖胖充满希望丶

    物联沃分享整理
    物联沃-IOTWORD物联网 » Appium Python PO模式实践指南

    发表回复