1. 项目概述:为什么选择这套组合拳?

如果你刚接触移动端自动化测试,面对市面上五花八门的工具和框架,可能会有点懵。我刚开始那会儿也这样,直到我反复折腾、踩了无数坑之后,才最终把“Appium + Python + 雷电模拟器”这套组合固定为我的入门和主力方案。这不是因为它最“高大上”,而是因为它对新手最友好、成本最低、生态最成熟,能让你用最小的代价跑通第一个自动化脚本,并建立起持续学习和迭代的信心。

简单来说, Appium 是一个开源的、跨平台的移动端自动化测试框架,它最大的魅力在于“一次编写,到处运行”。你写一套脚本,理论上可以测试Android、iOS、甚至Windows桌面应用。它底层基于WebDriver协议,这意味着如果你有Selenium做Web自动化的经验,上手会非常快。 Python 就不用多说了,语法简洁、库丰富、社区活跃,是自动化测试领域的“普通话”,几乎所有的测试框架都提供了Python客户端,学习资源和第三方支持是最多的。而 雷电模拟器 ,则解决了真机测试的硬件门槛和效率问题。它运行在电脑上,性能稳定、调试方便(直接截屏录屏)、可以多开并行,对于功能测试和回归测试来说,是绝佳的沙盒环境。

这套组合的核心价值在于,它构建了一个从零到一的完整闭环:用雷电模拟器提供稳定、可复现的测试环境;用Appium作为驱动这个环境的“遥控器”;用Python编写灵活、易读的测试逻辑。你不需要准备多台真机,不需要担心测试过程中的电量、网络波动,可以专注于测试用例的设计和脚本的编写本身。对于个人学习者、中小团队或者项目初期的快速验证阶段,性价比极高。

2. 环境搭建:一步一坑的避雷指南

环境搭建是劝退新手的第一个拦路虎。网上教程很多,但版本兼容性问题、路径配置错误、依赖缺失等问题层出不穷。下面我以Windows系统为例,带你走一遍最稳妥的搭建流程,并附上我踩过的坑和解决方案。

2.1 Python与IDE环境准备

首先确保你的电脑上安装了Python。我强烈建议使用Python 3.8或3.9版本,这是目前与各类库兼容性最好的版本。不要追求最新版,很多库的更新会滞后。

  1. 安装Python :从Python官网下载安装包。安装时务必勾选“Add Python to PATH”,这样可以在命令行直接使用 python pip 命令。安装完成后,打开命令提示符(CMD)或PowerShell,输入 python --version pip --version 验证是否成功。

  2. 选择IDE :PyCharm和VSCode是两大主流。PyCharm是专为Python设计的,开箱即用,对项目管理、虚拟环境、调试的支持非常完善,适合新手。VSCode更轻量,通过安装Python插件也能获得很好的体验,适合喜欢折腾和自定义的用户。我个人更推荐新手直接用PyCharm Community(免费版),省心。

  3. 创建虚拟环境 :这是一个好习惯,能为每个项目隔离Python包,避免版本冲突。在项目目录下,打开终端执行:

    python -m venv venv
    

    然后激活它(Windows):

    .\venv\Scripts\activate
    

    激活后,命令行前缀会显示 (venv) ,表示你正在虚拟环境中操作。

2.2 雷电模拟器安装与基础配置

雷电模拟器直接官网下载安装即可,建议安装64位版本。安装后启动,你会看到一个类似手机的界面。

这里有几个关键配置点,直接影响后续Appium的连接和测试:

  1. 开启开发者选项与USB调试 :这和真机一样。进入模拟器的“设置” -> “关于平板电脑” -> 连续点击“版本号”7次,开启开发者选项。返回上级菜单,进入“开发者选项”,开启“USB调试”。这是Appium能够连接和控制模拟器的前提。

  2. 修改模拟器设置(可选但重要)

    • 性能设置 :根据电脑配置,将CPU和内存调高(如4核,4096MB),运行会更流畅。
    • 分辨率设置 :建议设置为 1080x1920 (480dpi) ,这是一个非常通用的手机分辨率,方便脚本在不同设备间迁移。
    • 网络设置 :确保网络通畅。如果你需要抓包(比如用Burp Suite分析测试过程中的网络请求),可以将网络连接模式设置为“桥接模式”,并手动配置代理。但这属于进阶内容,入门阶段可以先不管。
  3. 记住模拟器的ADB连接信息 :启动模拟器后,打开命令行,进入雷电模拟器的安装目录(默认类似 C:\Program Files\ldplayer\ ),找到 adb.exe 。在同目录打开命令行,输入 adb devices 。你会看到一个设备号,格式通常为 127.0.0.1:5555 。这个地址和端口号就是Appium要连接的目标。

注意 :很多教程会让你安装独立的Android SDK并配置其ADB,这当然可以。但对于雷电模拟器,更简单的方法是直接使用它自带的ADB。但要小心“ADB冲突”,如果电脑上同时有多个ADB(比如Android Studio的),可能会导致端口占用或设备列表混乱。一个稳妥的办法是,将雷电模拟器安装目录下的 adb.exe 路径添加到系统环境变量 PATH 的最前面,确保命令行优先调用它。

2.3 Appium Server与Client的部署

Appium分为Server和Client两部分。Server是一个服务,负责接收我们编写的测试脚本(Client)发来的指令,并将其翻译成模拟器或真机可以理解的操作。Client就是我们的Python脚本,使用 Appium-Python-Client 这个库来和Server通信。

  1. 安装Appium Server :有两种方式。

    • 桌面版(Appium Desktop) :对于新手,我强烈推荐先从桌面版开始。它集成了Server和Inspector(一个用于定位元素的图形化工具),界面友好。从Appium官网下载安装即可。启动后,只需要点击“Start Server”按钮,一个服务就在本地(默认 http://127.0.0.1:4723 )跑起来了。
    • 命令行版(Appium via NPM) :需要先安装Node.js,然后通过npm安装: npm install -g appium 。安装后,在命令行输入 appium 即可启动服务。这种方式更灵活,适合集成到CI/CD流水线中,但初期调试不如桌面版直观。
  2. 安装Python客户端库 :在你的项目虚拟环境中,执行:

    pip install Appium-Python-Client
    

    这个库封装了与Appium Server交互的所有协议。

  3. 安装Appium Inspector(独立版) :Appium Desktop内置的Inspector在较新版本中已被标记为废弃。官方推荐使用独立的Appium Inspector。这是一个独立的应用程序,用于连接设备,查看UI层级结构,定位元素并获取其属性(如 resource-id , xpath , class 等),是编写脚本时不可或缺的“眼睛”。务必去官网下载安装。

3. 核心原理与关键配置解析

在开始写代码之前,理解Appium如何工作以及如何正确配置它,能让你在遇到问题时更快地定位原因。

3.1 Appium的工作机制:基于WebDriver的桥梁

你可以把Appium Server想象成一个翻译官。我们的Python脚本(Client)使用WebDriver协议(一种基于HTTP/JSON的协议)向Server发送请求,比如“点击某个按钮”。Appium Server收到请求后,会根据我们提供的“Desired Capabilities”配置,知道我们要操作的是哪个设备、哪个应用。然后,它调用对应平台的底层自动化框架(对于Android是UiAutomator2或Espresso,对于iOS是XCUITest),将这些高级指令转换成设备能执行的原生操作命令。最后,操作结果再通过相同的路径返回给我们的脚本。

为什么是UiAutomator2? 在Desired Capabilities中,你会看到一个参数 automationName: UiAutomator2 。这是Android平台目前推荐且稳定的自动化引擎。相比老旧的 UiAutomator1 ,它支持更丰富的操作(如长按、滑动到元素)、更好的等待策略,并且是Google官方维护的。除非有特殊兼容性问题,否则一律使用 UiAutomator2

3.2 Desired Capabilities:与设备对话的“合同”

这是Appium脚本中最重要的部分,它是一组键值对,定义了测试会话的所有要求。你可以把它理解为告诉Appium Server:“嗨,我要测试这样一个应用,在这样一个设备上,请按这些规则来。”

一个连接雷电模拟器,测试其内置“设置”应用的典型配置如下(Python字典格式):

from appium import webdriver

desired_caps = {
    # 必填:指定测试平台,这里是安卓
    'platformName': 'Android',
    # 必填:平台版本,在模拟器“设置-关于”里查看,或通过`adb shell getprop ro.build.version.release`获取
    'platformVersion': '9', # 根据你的模拟器安卓版本填写
    # 必填:设备名称,通过`adb devices`命令获取
    'deviceName': '127.0.0.1:5555', # 雷电模拟器的默认ADB地址
    # 必填:自动化引擎,安卓推荐UiAutomator2
    'automationName': 'UiAutomator2',
    # 必填:要启动的App包名
    'appPackage': 'com.android.settings',
    # 必填:要启动的App的主Activity名
    'appActivity': '.Settings',
    # 可选但重要:设置命令超时时间,单位秒
    'newCommandTimeout': 60,
    # 可选:是否在会话结束后不重置App状态(如不清空数据)
    'noReset': True,
    # 可选:设置Unicode输入,支持中文输入
    'unicodeKeyboard': True,
    'resetKeyboard': True,
}
  • appPackage appActivity :如何获取?有两个方法。一是问开发。二是使用ADB命令:先打开你要测试的App,然后在命令行输入 adb shell dumpsys window | findstr mCurrentFocus (Windows),输出结果中 / 后面的就是 appPackage ,再后面的就是 appActivity
  • deviceName :对于模拟器,使用 adb devices 列出的地址即可。对于真机,可以自定义一个易读的名字。
  • noReset :设为 True 时,Appium不会在测试开始前清除App的数据,这对于测试需要登录状态的连续场景非常有用。设为 False 则每次都会清空数据,回到初始状态。

3.3 元素定位:UI自动化的基石

自动化测试的本质就是模拟人对UI元素的操作。因此,如何精准地“找到”屏幕上的按钮、输入框等元素,是核心中的核心。Appium支持多种定位策略,和Selenium非常类似。

  1. ID定位 ( resource-id ) :最优先使用的方式,通常由开发在代码中指定,具有唯一性和稳定性。在Appium Inspector中查看元素的 resource-id 属性。

    driver.find_element(AppiumBy.ID, “com.example.app:id/login_button”)
    
  2. Accessibility ID定位 ( content-desc ) :如果元素有 content-desc (内容描述)属性,也可以用它定位。这个属性本意是给无障碍服务使用的,有时开发也会用它。

    driver.find_element(AppiumBy.ACCESSIBILITY_ID, “登录”)
    
  3. XPath定位 :最强大但也最脆弱的定位方式。它通过元素的层级路径来定位。当元素没有ID和Accessibility ID时可以使用,但应尽量避免使用绝对路径(以 / 开头),而是使用相对路径和属性组合。

    # 相对路径结合属性定位
    driver.find_element(AppiumBy.XPATH, “//android.widget.Button[@text=‘登录’]”)
    # 使用部分文本匹配
    driver.find_element(AppiumBy.XPATH, “//*[contains(@text, ‘部分文字’)]”)
    
  4. Class Name定位 :通过元素的类名定位,如 android.widget.EditText 。但通常一个界面上同类元素太多,不唯一,需要结合其他条件或使用 find_elements 取列表后按索引选择。

    # 找到所有输入框,取第一个
    driver.find_elements(AppiumBy.CLASS_NAME, “android.widget.EditText”)[0]
    
  5. Android UiAutomator定位 (UIAutomator2) :这是Android原生提供的定位方式,功能非常强大,可以通过复杂的条件组合来查找元素。

    from appium.webdriver.common.appiumby import AppiumBy
    # 文本匹配
    driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, ‘new UiSelector().text(“登录”)’)
    # 多个条件组合
    driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, ‘new UiSelector().className(“android.widget.Button”).text(“确认”)’)
    

实操心得 :定位元素的黄金法则是“优先使用ID,其次Accessibility ID,万不得已再用XPath,并尽量使用相对路径和属性组合”。XPath在页面结构变化时极易失效。每次使用Appium Inspector定位时,多观察元素的属性,思考哪种方式最稳定。将定位信息(如ID、XPath)单独管理在一个配置文件中,而不是硬编码在脚本里,是迈向编写可维护测试框架的第一步。

4. 第一个自动化脚本实战:从打开应用到完成操作

理论说再多,不如动手写一行代码。让我们来完成一个最简单的实战:打开雷电模拟器的“设置”应用,进入“无线和网络”菜单,然后返回。

4.1 脚本编写与逐行解读

首先,确保你的雷电模拟器已经启动,并且Appium Server(桌面版或命令行版)正在运行(默认端口4723)。

创建一个新的Python文件,比如 first_test.py

# 导入必要的库
from appium import webdriver
from appium.webdriver.common.appiumby import AppiumBy
from appium.options.android import UiAutomator2Options
import time

# 1. 定义设备能力配置
# 这里使用新的Options方式,比旧的字典方式更清晰、类型安全
options = UiAutomator2Options()
options.platform_name = ‘Android’
options.platform_version = ‘9’ # 请根据你的模拟器版本修改
options.device_name = ‘127.0.0.1:5555’
options.automation_name = ‘UiAutomator2’
# 我们要测试的是系统设置App
options.app_package = ‘com.android.settings’
options.app_activity = ‘.Settings’
# 设置超时和不清除数据
options.new_command_timeout = 60
options.no_reset = True

# 2. 连接Appium Server并启动会话
# 注意:这里的URL指向本地运行的Appium Server
driver = webdriver.Remote(‘http://127.0.0.1:4723’, options=options)

# 等待2秒,让应用界面完全加载稳定
time.sleep(2)

try:
    # 3. 定位并点击“网络和互联网”选项(文本可能因系统语言而异)
    # 先通过Appium Inspector找到这个元素的特征。这里假设其文本是“网络和互联网”
    network_item = driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR,
                                        ‘new UiSelector().text(“网络和互联网”)’)
    network_item.click()
    print(“已点击‘网络和互联网’.”)
    time.sleep(1) # 等待页面跳转

    # 4. 在“网络和互联网”页面,我们可以做更多操作,例如点击“Wi-Fi”
    # wifi_item = driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR,
    #                                 ‘new UiSelector().text(“Wi-Fi”)’)
    # wifi_item.click()
    # print(“已点击‘Wi-Fi’.”)
    # time.sleep(1)

    # 5. 按返回键,回到设置主页面
    driver.back()
    print(“已按返回键.”)
    time.sleep(1)

except Exception as e:
    # 如果出现任何错误(如元素找不到),打印错误信息
    print(f“执行过程中出现错误:{e}”)
    # 可以在这里截图,方便排查
    driver.save_screenshot(‘error_screenshot.png’)

finally:
    # 6. 无论成功与否,最后都要关闭会话,释放资源
    print(“测试结束,关闭驱动.”)
    driver.quit()

逐行解读与注意事项:

  • 新的Options方式 :代码中使用了 UiAutomator2Options() 来配置能力,这是Appium-Python-Client较新版本推荐的方式,比直接使用字典更规范,能提供更好的代码提示和类型检查。
  • 连接驱动 webdriver.Remote 是建立连接的关键。URL必须和你的Appium Server地址一致。
  • 隐式等待 vs 强制等待 ( time.sleep ) :脚本中使用了 time.sleep ,这是一种“强制等待”,会让脚本无条件暂停指定时间。这在快速原型或调试时可以用,但在正式脚本中是非常不好的习惯,因为它会浪费大量时间(即使元素早已加载好)。 最佳实践是使用“显式等待”
  • 异常处理 :使用 try...except...finally 结构是个好习惯。在 except 中捕获异常并截图,能极大提升调试效率。 finally 块确保无论测试成功还是失败, driver.quit() 都会被调用,关闭会话,避免资源泄露。
  • driver.back() :模拟设备的返回键。这是一个非常常用的导航操作。

4.2 优化:使用显式等待提升脚本健壮性

让我们用显式等待来替换那些不稳定的 time.sleep 。显式等待会告诉WebDriver:在抛出“找不到元素”异常之前,持续检查某个条件是否成立(比如元素是否可见、可点击),最多等待一段时间。

from appium.webdriver.common.appiumby import AppiumBy
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# … 前面的配置和连接代码不变 …

try:
    # 创建显式等待对象,最多等待10秒,每0.5秒检查一次条件
    wait = WebDriverWait(driver, 10)

    # 等待“网络和互联网”元素出现并可点击,然后点击它
    network_locator = (AppiumBy.ANDROID_UIAUTOMATOR, ‘new UiSelector().text(“网络和互联网”)’)
    network_item = wait.until(EC.element_to_be_clickable(network_locator))
    network_item.click()
    print(“已点击‘网络和互联网’.”)

    # 如果需要,同样用显式等待来操作Wi-Fi
    # wifi_locator = (AppiumBy.ANDROID_UIAUTOMATOR, ‘new UiSelector().text(“Wi-Fi”)’)
    # wifi_item = wait.until(EC.element_to_be_clickable(wifi_locator))
    # wifi_item.click()
    # print(“已点击‘Wi-Fi’.”)

    driver.back()
    print(“已按返回键.”)

except Exception as e:
    print(f“执行过程中出现错误:{e}”)
    driver.save_screenshot(‘error_screenshot.png’)

finally:
    print(“测试结束,关闭驱动.”)
    driver.quit()

为什么显式等待更好?

  1. 效率高 :如果元素在2秒内就加载好了,它不会傻等10秒,会立即执行后续操作。
  2. 健壮性强 :能有效应对网络波动、应用启动速度差异等导致的元素加载时间不确定的问题。
  3. 代码清晰 :明确表达了你“等待什么条件”,而不是“等待多少时间”。

5. 常见问题排查与实战技巧实录

即使按照步骤操作,你也一定会遇到各种问题。下面是我总结的常见“坑”及其解决方案。

5.1 连接类问题

问题1: adb devices 列表为空,或者找不到 127.0.0.1:5555 设备。

  • 可能原因1 :雷电模拟器未启动。确保模拟器已完全启动进入主界面。
  • 可能原因2 :ADB冲突。电脑上可能有多个ADB服务在运行(如Android Studio的)。解决:关闭所有可能占用ADB的程序,或在命令行执行 adb kill-server ,然后重新执行 adb devices 。最根本的解决方法是确保环境变量 PATH 中,雷电模拟器的 adb 路径在最前面。
  • 可能原因3 :模拟器的ADB调试未开启。确认模拟器“开发者选项”中的“USB调试”已打开。

问题2:Appium Server启动失败,或脚本报错 Unable to create a new remote session

  • 可能原因1 :端口冲突。Appium默认使用4723端口。确保没有其他程序占用该端口。可以通过 netstat -ano | findstr :4723 (Windows)检查。
  • 可能原因2 Desired Capabilities 配置错误。仔细检查每一项,特别是 platformVersion deviceName appPackage appActivity deviceName 必须和 adb devices 列出的完全一致。 appPackage appActivity 必须正确。
  • 可能原因3 :Appium Server版本与Client库版本不兼容。尝试使用相对稳定的版本组合,例如Appium Server 2.x 搭配 appium-python-client 的最新稳定版。查看官方文档的版本兼容性说明。

5.2 元素操作类问题

问题3:脚本报错 NoSuchElementException ,找不到元素。

  • 可能原因1 :页面尚未加载完成。 解决方案 :使用显式等待( WebDriverWait )代替硬性等待( time.sleep )。
  • 可能原因2 :定位器写错了。 解决方案 :使用Appium Inspector重新捕获元素,核对定位器字符串。特别注意XPath是否因页面动态内容而失效。优先尝试其他定位方式,如ID或Accessibility ID。
  • 可能原因3 :元素在WebView或混合应用中。 解决方案 :需要切换上下文(Context)。使用 driver.contexts 获取所有上下文,然后切换到对应的WebView上下文(通常名字包含 WEBVIEW )再进行操作。这是一个进阶话题,但很常见。
  • 可能原因4 :元素在弹窗、下拉菜单或新的Activity中。 解决方案 :确保你的操作(如点击)触发了界面变化后,需要重新定位新界面上的元素。有时需要处理系统弹窗(如权限申请)。

问题4:可以找到元素,但点击( click() )没反应。

  • 可能原因1 :元素不可点击。 解决方案 :使用 element_to_be_clickable 条件进行显式等待,确保元素是可交互状态。
  • 可能原因2 :元素被其他元素(如透明遮罩层)遮挡。 解决方案 :尝试使用TouchAction(旧版)或W3C Actions(新版)提供更精确的点击坐标,或者先处理掉遮挡层。
  • 可能原因3 :需要的是“轻触”而不是“点击”,或者需要更复杂的操作(如长按)。 解决方案 :使用 driver.tap([(x, y)], duration) 进行轻触,或使用Actions API进行长按、滑动等操作。

5.3 性能与稳定性技巧

  1. 截图与录屏是救命稻草 :在关键步骤前后、尤其是断言失败或发生异常时,自动截图。Appium提供了 driver.save_screenshot(‘filename.png’) 方法。对于复杂问题,可以考虑录屏。
  2. 使用Page Object模式(PO) :当测试用例越来越多时,不要把定位器和操作逻辑都堆在一个脚本里。将每个页面封装成一个类,页面的元素定位器作为类的属性,页面的操作(如登录、搜索)作为类的方法。这样能使代码结构清晰,易于维护,元素定位器变更只需修改一处。
  3. 配置 autoGrantPermissions :在Desired Capabilities中设置 ‘autoGrantPermissions’: True ,可以让Appium自动处理应用弹出的运行时权限请求,避免脚本被弹窗打断。
  4. 处理应用升级/安装弹窗 :自动化安装或启动应用时,可能会遇到“是否升级”、“安装风险提示”等系统弹窗。这些弹窗不属于你的应用,需要特殊处理。可以尝试用ADB命令提前安装,或者在脚本中加入判断和处理这些弹窗的逻辑(通常通过识别弹窗上的“确定”、“安装”按钮文本)。
  5. 日志分析 :当脚本运行出错时,不要只看Python的报错信息。仔细查看Appium Server的控制台输出日志,里面包含了更详细的底层交互信息,是排查问题的关键。

6. 项目结构与脚本组织入门

当你掌握了单个脚本的编写后,很快就会面临如何管理多个测试用例、测试数据和公共代码的问题。一个好的项目结构能极大提升协作效率和维护性。

一个典型的入门级项目结构可以这样组织:

your_automation_project/
├── config/ # 配置文件目录
│ ├── __init__.py
│ └── config.py # 存放设备配置、App信息、服务器地址等
├── pages/ # 页面对象目录
│ ├── __init__.py
│ ├── base_page.py # 所有Page类的基类,封装公共方法
│ ├── main_page.py # 例如,应用主页的Page类
│ └── login_page.py # 登录页的Page类
├── test_cases/ # 测试用例目录
│ ├── __init__.py
│ ├── test_login.py # 登录功能测试用例
│ └── test_search.py # 搜索功能测试用例
├── utils/ # 工具函数目录
│ ├── __init__.py
│ ├── logger.py # 日志记录工具
│ └── common_actions.py # 封装滑动、截图等公共操作
├── reports/ # 测试报告目录(可自动生成)
├── screenshots/ # 失败截图目录
├── requirements.txt # 项目依赖包列表
└── run_tests.py # 测试运行主入口

简要说明:

  • config.py :集中管理配置,避免硬编码。
    # config.py
    class Config:
        APPIUM_SERVER = ‘http://127.0.0.1:4723’
        PLATFORM_NAME = ‘Android’
        PLATFORM_VERSION = ‘9’
        DEVICE_NAME = ‘127.0.0.1:5555’
        APP_PACKAGE = ‘com.example.myapp’
        APP_ACTIVITY = ‘.MainActivity’
    
  • base_page.py :所有页面类的父类,可以封装查找元素的通用方法、日志记录、截图等。
    # pages/base_page.py
    from appium.webdriver.webdriver import WebDriver
    class BasePage:
        def __init__(self, driver: WebDriver):
            self.driver = driver
        def find(self, locator):
            # 可以在这里加入显式等待和日志
            print(f“Finding element with locator: {locator}”)
            return self.driver.find_element(*locator)
    
  • login_page.py :继承 BasePage ,封装登录页的所有元素和操作。
    # pages/login_page.py
    from appium.webdriver.common.appiumby import AppiumBy
    from .base_page import BasePage
    class LoginPage(BasePage):
        # 元素定位器
        username_input = (AppiumBy.ID, ‘com.example.app:id/username’)
        password_input = (AppiumBy.ID, ‘com.example.app:id/password’)
        login_button = (AppiumBy.ID, ‘com.example.app:id/login’)
        # 页面操作方法
        def login(self, username, password):
            self.find(self.username_input).send_keys(username)
            self.find(self.password_input).send_keys(password)
            self.find(self.login_button).click()
    
  • test_login.py :使用Page Object来组织测试用例,清晰易懂。
    # test_cases/test_login.py
    import pytest
    from appium import webdriver
    from config.config import Config
    from pages.login_page import LoginPage
    class TestLogin:
        @pytest.fixture(scope=‘class’)
        def driver(self):
            # 初始化驱动
            caps = { … } # 从Config类读取
            driver = webdriver.Remote(Config.APPIUM_SERVER, options=caps)
            yield driver
            driver.quit()
        def test_valid_login(self, driver):
            login_page = LoginPage(driver)
            login_page.login(‘correct_user’, ‘correct_pwd’)
            # 添加断言,验证登录成功
            assert driver.current_activity == ‘.MainActivity’
    
  • run_tests.py :可以使用 pytest 框架来发现并运行所有测试用例,生成报告。

采用这样的结构,当登录页面的输入框ID发生变化时,你只需要修改 login_page.py 文件中的一个常量,所有用到这个输入框的测试用例都会自动生效,维护成本大大降低。这是从小脚本走向可维护自动化项目的关键一步。

更多推荐