Appium+Python 实现移动应用自动化测试:从基础到实战

在移动应用开发中,自动化测试是保障产品质量的关键环节。Appium 作为一款跨平台的移动自动化工具,支持 iOS 和 Android,且能与 Python 等主流语言结合,成为很多开发者的首选。本文将基于实际项目代码,带你掌握 Appium+Python 的核心用法,实现从应用登录到功能循环测试的全流程自动化。

一、环境准备:搭建 Appium 自动化基础

在开始编写代码前,需要先搭建好运行环境,确保设备、工具和依赖都配置到位。

1. 核心工具与依赖安装

  • Appium Server:用于管理自动化会话的服务端,可通过Appium 官网下载桌面版,或通过 npm 安装命令行版(npm install -g appium)。
  • Android SDK:提供 ADB(Android 调试桥)等工具,需配置ANDROID_HOME环境变量,并将platform-tools目录加入 Path(确保adb命令可全局执行)。
  • Python 客户端:安装 Appium Python 库,执行pip install Appium-Python-Client。
  • 测试设备:一台开启 "USB 调试" 的 Android 真机(或模拟器),确保通过 USB 连接电脑后,adb devices命令能识别到设备。

如果不会安装的话可以参考我之前写的博客Appium下载安装配置保姆教程(图文详解)

2. 设备连接检查

在编写代码前,先用 ADB 命令确认设备已正常连接:

bash 复制代码
# 查看已连接的设备
adb devices

若输出类似1234567890ABCDEF device,说明设备连接成功(device状态表示可用)。

二、核心操作:Appium+Python 基础用法

Appium 的核心是通过客户端代码与 Appium Server 通信,实现对设备的控制。以下是最常用的基础操作,也是自动化脚本的骨架。

1. 初始化 Appium 会话

要控制设备,需先创建一个 Appium 会话(Session),通过配置 "期望能力"(Desired Capabilities)指定设备和应用信息。

python 复制代码
from appium import webdriver
from appium.options.android import UiAutomator2Options

# 配置期望能力(Desired Capabilities)
CAPABILITIES = {
    "platformName": "Android",  # 平台(Android/iOS)
    "deviceName": "1234567890ABCDEF",  # 设备序列号(通过adb devices获取)
    "appPackage": "com.jlfc.tml",  # 应用包名
    "appActivity": ".MainActivity",  # 启动Activity
    "automationName": "UiAutomator2",  # 自动化引擎(Android推荐UiAutomator2)
    "noReset": True  # 不重置应用数据(避免每次启动都清除缓存)
}

# 初始化会话:连接Appium Server(默认地址http://localhost:4723/wd/hub)
options = UiAutomator2Options().load_capabilities(CAPABILITIES)
driver = webdriver.Remote("http://localhost:4723/wd/hub", options=options)
  • platformName:指定测试平台(必须正确,否则无法连接)。
  • appPackage和appActivity:确定要启动的应用及入口(可通过adb命令获取,前文已讲)。
bash 复制代码
adb shell dumpsys window | findstr "mCurrentFocus"
  • automationName:指定自动化引擎,Android 推荐UiAutomator2(支持最新系统版本)。

2. 元素定位与操作

自动化的核心是 "找到元素并操作"。Appium 支持多种定位方式,常用的有IDXPath文本,以下是实战中最常用的两种:

(1)通过 ID 定位(最稳定)

元素的resource-id是开发时设置的唯一标识,优先用 ID 定位:

python 复制代码
from appium.webdriver.common.appiumby import AppiumBy

# 定位"管理员用户"按钮(ID为com.jlfc.tml:id/txt_user_admin)
admin_btn = driver.find_element(by=AppiumBy.ID, value="com.jlfc.tml:id/txt_user_admin")
admin_btn.click()  # 点击按钮

(2)通过 XPath 定位(最灵活)

当元素无唯一 ID 时,可用 XPath 结合文本、属性等定位:

python 复制代码
# 定位文本为"固件版本升级"的选项
upgrade_item = driver.find_element(
    by=AppiumBy.XPATH, 
    value="//android.widget.TextView[@text='固件版本升级']"
)
upgrade_item.click()

# 定位包含"登录"文本的按钮
login_btn = driver.find_element(
    by=AppiumBy.XPATH, 
    value="//android.widget.Button[contains(@text, '登录')]"
)

3. 等待机制:避免 "元素未加载" 问题

应用界面加载需要时间,直接定位元素可能导致 "找不到元素" 错误。需使用显式等待,等待元素处于可操作状态后再执行操作:

python 复制代码
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException

def wait_element_clickable(driver, locator, timeout=10):
    """等待元素可点击"""
    try:
        # 等待timeout秒,直到元素可点击
        return WebDriverWait(driver, timeout).until(
            EC.element_to_be_clickable(locator)
        )
    except TimeoutException:
        raise Exception(f"超时未找到可点击元素:{locator}")

# 用法:等待"登录按钮"可点击后点击
login_btn_locator = (AppiumBy.ID, "com.jlfc.tml:id/btn_login")
wait_element_clickable(driver, login_btn_locator).click()
  • 显式等待比time.sleep()更高效(无需固定等待时间,元素加载完成后立即执行)。
  • 超时时间根据页面复杂度设置(一般 5-15 秒)。

4. 常用交互操作

除了点击,Appium 还支持输入文本、滑动、返回主页等常用操作:

python 复制代码
# 输入文本(如账号密码)
username_input = driver.find_element(by=AppiumBy.ID, value="com.jlfc.tml:id/edit_username")
username_input.send_keys("yy_after")  # 输入账号

# 滑动屏幕(上滑,参数:起始x、起始y、结束x、结束y、持续时间)
def swipe_up(driver):
    size = driver.get_window_size()  # 获取屏幕尺寸
    driver.swipe(
        size["width"] * 0.5,  # 起始x(屏幕中间)
        size["height"] * 0.8,  # 起始y(屏幕下方)
        size["width"] * 0.5,  # 结束x(屏幕中间)
        size["height"] * 0.2,  # 结束y(屏幕上方)
        500  # 滑动持续时间(毫秒)
    )

# 返回手机主页(按Home键,keycode=3)
driver.press_keycode(3)

5. 关闭会话

测试结束后,需关闭会话释放资源:

python 复制代码
driver.quit()  # 关闭当前会话,释放设备

三、实战案例:实现应用登录与循环测试

基于以上基础,我们可以组合出完整的自动化场景。以下面应用为例,实现 "管理员登录" 和 "固件升级循环测试" 两个核心流程。

1. 管理员登录流程

登录是大多数应用的基础操作,需处理 "应用已打开" 和 "需重新启动应用" 两种场景:

python 复制代码
def login_admin(driver):
    # 检查是否已显示"管理员用户"按钮
    admin_btn_locator = (AppiumBy.ID, "com.jlfc.tml:id/txt_user_admin")
    try:
        # 若已显示,直接点击
        wait_element_clickable(driver, admin_btn_locator, timeout=2).click()
        print("已点击管理员用户按钮")
    except TimeoutException:
        # 若未显示,返回主页并重启应用
        driver.press_keycode(3)  # 返回主页
        time.sleep(2)
        
        # 滑动查找应用图标并点击(最多滑3次)
        max_scrolls = 3
        for i in range(max_scrolls):
            try:
                # 定位应用图标(文本为"唐米力")
                app_icon = wait_element_clickable(
                    driver, 
                    (AppiumBy.XPATH, '//*[@text="唐米力"]'), 
                    timeout=5
                )
                app_icon.click()
                print("已启动应用")
                time.sleep(5)  # 等待应用启动
                break
            except TimeoutException:
                if i == max_scrolls - 1:
                    raise Exception("未找到应用图标")
                swipe_up(driver)  # 上滑屏幕
                print(f"已上滑{i+1}次")
        
        # 启动后点击管理员按钮
        wait_element_clickable(driver, admin_btn_locator).click()
    
    # 输入账号密码并登录
    wait_element_clickable(driver, (AppiumBy.ID, "com.jlfc.tml:id/edit_username")).send_keys("yy")
    wait_element_clickable(driver, (AppiumBy.ID, "com.jlfc.tml:id/edit_password")).send_keys("123456")
    wait_element_clickable(driver, (AppiumBy.ID, "com.jlfc.tml:id/btn_login")).click()
    
    # 验证登录成功(检查"自动炒菜"文本是否显示)
    wait_element_clickable(driver, (AppiumBy.XPATH, "//*[@text='自动炒菜']"), timeout=15)
    print("管理员登录成功")

2. 固件升级循环测试

很多场景需要重复执行某一操作(如多次测试固件升级),可通过循环实现,并加入异常处理确保稳定性:

python 复制代码
def run_firmware_upgrade(driver, run_count=10):
    """循环执行固件升级测试"""
    stop_flag = False  # 用于标记是否停止后续测试
    for i in range(run_count):
        if stop_flag:
            print("检测到错误,停止后续升级测试")
            break
        
        try:
            print(f"\n===== 第{i+1}次固件升级 =====")
            
            # 检查会话是否有效(避免设备断开)
            try:
                driver.current_activity  # 获取当前Activity,验证会话
            except Exception:
                raise Exception("会话已失效,需重新初始化")
            
            # 进入设置页面
            wait_element_clickable(driver, (AppiumBy.ID, "com.jlfc.tml:id/img_settings")).click()
            
            # 点击"固件版本升级"
            wait_element_clickable(
                driver, 
                (AppiumBy.XPATH, "//*[@text='固件版本升级' and @resource-id='android:id/title']")
            ).click()
            
            # 点击确认升级
            wait_element_clickable(
                driver, 
                (AppiumBy.ID, "com.jlfc.tml:id/btn_confirm")
            ).click()
            
            # 等待升级完成(最长360秒)
            wait_element_clickable(
                driver, 
                (AppiumBy.ID, "com.jlfc.tml:id/btn_login"),  # 升级后回到登录页
                timeout=360
            )
            print(f"第{i+1}次升级完成,已返回登录页")
            
            # 点击登录按钮,准备下一次测试
            wait_element_clickable(driver, (AppiumBy.ID, "com.jlfc.tml:id/btn_login")).click()
            
        except Exception as e:
            # 捕获异常,标记停止后续测试
            print(f"第{i+1}次升级失败:{str(e)}")
            stop_flag = True
            # 可在此处添加截图功能(见下文)

3. 异常处理与截图

测试出错时,截图能帮助定位问题,可封装一个截图函数:

python 复制代码
import os
from datetime import datetime

def take_screenshot(driver, name):
    """保存截图到本地"""
    # 创建截图目录
    screenshot_dir = "screenshots"
    if not os.path.exists(screenshot_dir):
        os.makedirs(screenshot_dir)
    
    # 截图文件名(包含时间戳)
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    filename = f"{screenshot_dir}/{name}_{timestamp}.png"
    
    # 保存截图
    driver.save_screenshot(filename)
    print(f"截图已保存:{filename}")
    return filename

# 用法:在异常时调用
try:
    # 测试步骤...
except Exception as e:
    take_screenshot(driver, "upgrade_failure")
    raise e

四、自动化测试最佳实践

  1. 优先使用稳定的定位方式:ID > XPath(属性组合) > 文本(文本可能随语言变化)。
  2. 合理设置等待时间:避免用time.sleep(),多用显式等待;根据页面加载速度调整超时时间。
  3. 处理会话失效:设备断开、应用崩溃可能导致会话失效,需在关键步骤前检查会话状态(如driver.current_activity)。
  4. 循环测试加中断机制:重复测试时,一旦出现致命错误,立即停止后续执行(如上文的stop_flag),避免无效执行。
  5. 及时清理资源:测试结束后务必调用driver.quit(),释放设备连接,避免影响其他测试。

到这里我的分享就结束了,欢迎到评论区探讨交流!!

💖如果觉得有用的话还请点个赞吧 💖

相关推荐
阿祖_in_coding6 天前
混合App(Hybrid App)自动化测试理解
appium
returnthem13 天前
安装Appium
appium
seabirdssss18 天前
Appium 在小米平板上的安装受限与闪退排查
android·appium·电脑
小陈的进阶之路22 天前
Selenium 滑动 vs Appium 滑动
python·selenium·测试工具·appium
小陈的进阶之路22 天前
Appium 自动化测试笔记
笔记·appium
linglan42824 天前
APPium环境配置
appium·自动化
lifewange1 个月前
Appium是什么
appium·压力测试
柚子+1 个月前
Appium+python+雷电模拟器自动化测试入门
数据库·python·appium
@Aurora.2 个月前
【GUI自动化测试】--基于QQ音乐项目的GUI自动化测试
appium