Python+Selenium+Appium自动化测试实战:从环境搭建到框架设计

📅 2026/7/7 21:04:45 👁️ 阅读次数 📝 编程学习
Python+Selenium+Appium自动化测试实战:从环境搭建到框架设计

1. 项目概述:为什么我们需要自动化测试?

在软件研发的日常里,测试是个绕不开的活儿。功能越复杂,迭代越快,手动点点点的压力就越大。今天改个按钮,明天加个字段,每次上线前都得把核心流程从头到尾走一遍,费时费力不说,还容易因为疲劳而出错。这就是为什么“自动化测试”从一个加分项,变成了很多团队的基础设施。它本质上是一套脚本,能模拟人的操作,自动执行预设的测试用例,并验证结果。想象一下,每次代码提交后,自动跑一遍几百个测试用例,半小时出结果,这给开发和测试同学带来的不仅是效率提升,更是信心的保障。

而说到自动化测试,尤其是UI层面的自动化,SeleniumAppium是两座绕不开的大山。Selenium主攻Web浏览器自动化,从Chrome到Firefox,它都能驾驭;Appium则继承了Selenium的WebDriver协议,将其扩展到了移动端(iOS, Android),甚至桌面应用。它们的核心思想一致:通过一个中间服务器(Driver)接收指令,再去操控真实的应用。而Python,以其简洁的语法和丰富的生态,成为了连接这两大工具、编写自动化脚本的绝佳粘合剂。这个组合,能让你用一套相对统一的思路和代码结构,去应对Web和App的自动化测试挑战。

所以,掌握这个技术栈,意味着你不仅能为Web产品构建自动化测试防线,还能将能力平滑扩展到移动端,大大提升个人在测试开发领域的竞争力和解决实际问题的能力。接下来,我会带你从零开始,搭建环境、理解核心概念、编写脚本,并分享那些只有踩过坑才知道的实战经验。

2. 环境搭建与核心工具解析

工欲善其事,必先利其器。在开始写第一行自动化脚本之前,我们需要把“战场”布置好。这个过程可能会遇到一些环境配置的坑,我会把关键步骤和避坑点都讲清楚。

2.1 Python环境:不只是安装那么简单

Python是这一切的基石。很多新手卡在第一步,不是没安装Python,而是环境没弄对。

安装与版本选择:目前,Python 3.8到3.11都是比较稳定且兼容性好的选择。直接从Python官网下载安装包,安装时务必勾选“Add Python to PATH”,这是为了能在命令行任何位置直接调用pythonpip命令。安装完成后,打开终端(Windows是CMD或PowerShell,Mac/Linux是Terminal),输入python --version,能正确显示版本号即表示成功。

注意:如果你的电脑上原本有多个Python版本(比如系统自带的Python 2.7),可能需要通过py -3(Windows)或明确使用python3pip3(Mac/Linux)来指定版本。混乱的Python环境是后续一切问题的根源。

包管理工具pip与虚拟环境:pip是Python的包安装工具。但强烈不建议把所有包都安装在全局环境。使用虚拟环境(Virtual Environment)可以为每个项目创建独立的Python运行环境,避免包版本冲突。这是专业开发的第一步。

创建虚拟环境的命令很简单:

# 在当前目录下创建一个名为 `venv` 的虚拟环境 python -m venv venv

激活环境:

  • Windows:venv\Scripts\activate
  • Mac/Linux:source venv/bin/activate

激活后,命令行提示符前通常会显示(venv),表示你已进入该虚拟环境。之后所有通过pip install安装的包,都只存在于这个环境中。

IDE选择:VS Code和PyCharm是两大主流。VSCode轻量、插件丰富,配置稍复杂;PyCharm开箱即用,对Python项目支持极好,社区版就足够我们使用。选择哪个看个人喜好,但一个好的IDE能提供的代码提示、调试功能,对效率提升巨大。

2.2 Selenium与WebDriver:操控浏览器的核心

Selenium本身是一个库,但它需要对应的浏览器驱动(WebDriver)才能实际控制浏览器。你可以把Selenium想象成大脑,发出“点击这里”、“输入文字”的指令;而WebDriver就是手和眼睛,负责执行指令并反馈浏览器的状态。

安装Selenium库:在激活的虚拟环境中,一行命令搞定:

pip install selenium

配置浏览器驱动:这是第一个常见的坑。以最常用的Chrome为例:

  1. 首先,查看你电脑上Chrome浏览器的版本(在浏览器地址栏输入chrome://version/查看)。
  2. 然后,访问ChromeDriver的官方下载站点(或国内镜像站),下载与你的Chrome浏览器主版本号完全一致的ChromeDriver。
  3. 下载后,得到一个可执行文件(如chromedriver.exechromedriver)。你需要让Selenium能找到它,通常有三种方式:
    • 放入系统PATH:将文件放在系统环境变量PATH包含的目录下,如/usr/local/bin(Mac/Linux)或C:\Windows(Windows)。这是最一劳永逸的方法。
    • 指定路径:在代码中初始化浏览器时,通过service参数指定驱动文件的完整路径。
    • 使用第三方工具:像webdriver-manager这样的库可以自动下载和管理驱动版本,非常方便。安装pip install webdriver-manager,然后在代码中引用即可。

我个人的经验是,在团队协作或持续集成(CI)环境中,使用webdriver-manager能省去很多维护驱动版本的麻烦;在个人学习初期,手动指定路径更直观。

2.3 Appium与服务端配置:连接移动设备的桥梁

Appium的架构比Selenium复杂一些。它是一个C/S架构,你需要启动一个Appium服务器,然后你的Python脚本作为客户端向这个服务器发送指令,服务器再通过设备自身的自动化框架(如Android的UiAutomator2)来操控设备。

安装Appium Server:现在官方推荐使用Appium 2.0,并通过Node.js的包管理器npm来安装。首先确保安装了Node.js,然后通过命令行安装:

npm install -g appium

安装完成后,执行appium -v检查版本。运行appium命令即可启动服务器,默认监听本地的4723端口。

安装Appium驱动(Driver):Appium 2.0引入了驱动概念,你需要为你想要自动化的平台安装对应的驱动。比如对于Android,最常用的是uiautomator2驱动。

# 在Appium Server安装后,执行以下命令安装Android驱动 appium driver install uiautomator2

安装Appium Python客户端:这就是我们的脚本将要使用的库。它继承了Selenium的客户端,所以安装它时会自动安装Selenium。

pip install Appium-Python-Client

配置移动设备环境

  • Android:需要安装Android SDK,并配置ANDROID_HOME环境变量指向SDK路径。同时,确保adb(Android调试桥)工具可用。通过USB连接真机或启动模拟器,在开发者选项中开启“USB调试”。在命令行输入adb devices,能看到设备列表即表示连接成功。
  • iOS:需要Xcode、Xcode Command Line Tools以及WebDriverAgent等,配置更为复杂,通常需要在Mac系统上进行。

实操心得:环境配置是劝退新手的第一个门槛。我的建议是,严格按照官方文档一步步来,并善用搜索引擎。遇到报错,把完整的错误信息复制出来搜索,你遇到的问题,大概率别人已经遇到过并解决了。另外,对于Android,使用模拟器(如Android Studio自带的AVD)进行初期学习是个不错的选择,避免真机各种兼容性问题。

3. 核心概念与脚本结构深度解析

环境搭好了,我们得先理解一下我们到底在写什么。自动化测试脚本不是随意堆砌的命令,它有清晰的结构和核心对象。

3.1 WebDriver与Session:会话是一切的基础

无论是Selenium还是Appium,你的脚本与浏览器/设备交互的起点都是创建一个WebDriver对象。这个创建过程,本质上是在远程的Selenium Server或Appium Server上开启一个会话(Session)

在Selenium中,你直接初始化一个浏览器驱动:

from selenium import webdriver from selenium.webdriver.chrome.service import Service from webdriver_manager.chrome import ChromeDriverManager # 使用webdriver-manager自动管理驱动 service = Service(ChromeDriverManager().install()) driver = webdriver.Chrome(service=service) # 此时,一个Chrome浏览器窗口被打开,并与一个唯一的Session ID绑定

在Appium中,过程类似,但需要更多的配置信息(Capabilities)来告诉服务器你要控制什么设备、什么应用:

from appium import webdriver from appium.options.android import UiAutomator2Options # 定义Capabilities options = UiAutomator2Options() options.platform_name = 'Android' options.automation_name = 'uiautomator2' options.device_name = '你的设备名' # 通过`adb devices`获取 options.app_package = 'com.android.settings' # 系统设置App的包名 options.app_activity = '.Settings' # 设置App的主Activity # 连接到本地Appium服务器,并创建会话 driver = webdriver.Remote('http://localhost:4723', options=options)

这个driver对象就是你后续所有操作的指挥官。通过它,你可以查找元素、点击、输入、滑动等。

3.2 Capabilities详解:告诉服务器你的意图

Capabilities是Appium中极其重要的一环,它是一组键值对,用于描述自动化会话的各方面属性。你可以把它理解为一份“需求说明书”。

  • platformName: 平台名称,如'Android''iOS'
  • automationName: 自动化引擎,Android上常用'uiautomator2',iOS上常用'xcuitest'
  • deviceName: 设备名称,可以是任意字符串,但在连接多台设备时需要用来区分。
  • appPackageappActivity: 用于指定要启动的Android应用。appPackage是应用包名,appActivity是入口活动名。可以通过adb shell dumpsys window | findstr mCurrentFocus(Windows)或adb shell dumpsys window | grep mCurrentFocus(Mac/Linux)来获取当前前台应用的这两个值。
  • app: 如果要测试的App尚未安装,可以指定APK文件或IPA文件的本地路径,Appium会先安装再启动。
  • noReset: 设为True时,会话结束后不会重置App数据(如登录状态)。这在测试需要登录的流程时非常有用。
  • fullReset: 设为True时,会在会话开始前卸载并重新安装App。通常用于干净的测试环境。

注意事项:Capabilities的写法在Appium 2.x的Python客户端中有所变化,推荐使用上面示例中的Options模式(如UiAutomator2Options()),它比旧的字典方式更清晰,且能自动处理appium:前缀,避免拼写错误。

3.3 元素定位:自动化测试的“眼睛”

脚本要操作界面上的按钮、输入框,首先得找到它们。这就是元素定位。定位的准确性直接决定了脚本的稳定性。

Selenium/Appium支持的定位方式

  1. ID:最理想的方式,唯一且稳定。driver.find_element(By.ID, “element_id”)
  2. Name:类似于ID,但可能不唯一。
  3. XPath:功能最强大的定位方式,可以通过层级、属性、文本等任何信息来定位元素。但也是稳定性相对较差的一种,因为UI结构一变,XPath可能就失效了。//android.widget.TextView[@text=”确定”]
  4. Accessibility ID (Appium)/AccessibilityIdentifier (iOS):在移动端开发中,为元素添加的可访问性ID,专为自动化测试设计,是移动端首选的定位方式。在Appium中对应AppiumBy.ACCESSIBILITY_ID
  5. Class Name:通过元素类型定位,如android.widget.Button,通常不唯一,需要结合其他条件。
  6. CSS Selector (Selenium Web):在Web自动化中非常高效和强大的定位方式。

定位策略与最佳实践

  • 优先级ID/Accessibility ID>Name>CSS Selector>XPath
  • 使用相对XPath:尽量避免使用绝对路径(如/html/body/div[1]/div[2]/button),而使用相对路径结合属性(如//button[@id=’submit’])。
  • 等待机制:元素可能因为网络、渲染速度而尚未出现。直接定位会抛出NoSuchElementException。必须结合显式等待
from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By # 等待最多10秒,直到ID为‘submit’的元素出现 element = WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.ID, “submit”)) ) element.click()

显式等待是编写稳定自动化脚本的基石,它按条件轮询查找,避免了硬性等待(time.sleep)造成的资源浪费和不稳定。

4. 从零编写你的第一个自动化测试脚本

理论说得再多,不如动手写一个。我们分别用Selenium和Appium写一个最简单的脚本,感受一下完整的流程。

4.1 Selenium实战:自动化Web搜索

我们的目标是:打开百度首页,在搜索框输入“自动化测试”,点击搜索按钮,然后验证搜索结果页面标题是否包含关键词。

import unittest from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.chrome.service import Service from webdriver_manager.chrome import ChromeDriverManager class TestBaiduSearch(unittest.TestCase): """一个简单的百度搜索测试用例""" def setUp(self): """每个测试方法执行前运行,用于初始化""" # 使用webdriver-manager自动处理ChromeDriver service = Service(ChromeDriverManager().install()) self.driver = webdriver.Chrome(service=service) self.driver.maximize_window() # 最大化窗口 self.driver.get(“https://www.baidu.com“) # 打开百度 self.wait = WebDriverWait(self.driver, 10) # 创建一个等待对象 def tearDown(self): """每个测试方法执行后运行,用于清理""" if self.driver: self.driver.quit() def test_search_automation(self): """测试搜索功能""" # 1. 定位搜索框,并输入关键词 search_box = self.wait.until( EC.presence_of_element_located((By.ID, “kw”)) # 百度搜索框的ID是‘kw’ ) search_box.send_keys(“自动化测试“) # 2. 定位搜索按钮,并点击 search_button = self.wait.until( EC.element_to_be_clickable((By.ID, “su”)) # 百度搜索按钮的ID是‘su’ ) search_button.click() # 3. 等待搜索结果页面加载,并验证标题 self.wait.until( EC.title_contains(“自动化测试“) # 等待页面标题包含“自动化测试” ) # 断言:当前标题应包含“自动化测试” self.assertIn(“自动化测试“, self.driver.title) print(f“当前页面标题为:{self.driver.title}, 断言通过!“) if __name__ == ‘__main__‘: unittest.main()

脚本解读与技巧

  • 我们使用了Python自带的unittest框架来组织测试,setUptearDown是固定的准备和清理方法。
  • WebDriverWait配合expected_conditions是黄金搭档,presence_of_element_located等待元素出现在DOM中,element_to_be_clickable等待元素可点击,这比单纯等待出现更可靠。
  • send_keys方法用于输入文本,甚至可以模拟键盘操作,如send_keys(Keys.ENTER)
  • 断言self.assertIn是测试的核心,用于验证实际结果是否符合预期。

4.2 Appium实战:自动化Android设置

我们的目标是:在Android设备的“设置”应用中,找到并点击“电池”选项。

import unittest from appium import webdriver from appium.options.android import UiAutomator2Options from appium.webdriver.common.appiumby import AppiumBy from appium.webdriver.common.touch_action import TouchAction import time class TestAndroidSettings(unittest.TestCase): """Android设置应用自动化测试""" def setUp(self): """初始化Appium驱动""" # 配置Capabilities options = UiAutomator2Options() options.platform_name = ‘Android‘ options.automation_name = ‘uiautomator2‘ # device_name可以是adb devices列出的设备名,或模拟器名称(如’emulator-5554‘) options.device_name = ‘emulator-5554‘ # 测试系统自带的设置应用 options.app_package = ‘com.android.settings‘ options.app_activity = ‘.Settings‘ # 不重置应用数据,避免每次都要看引导页 options.no_reset = True # Appium服务器地址 appium_server_url = ‘http://localhost:4723‘ # 创建驱动,即启动一个Appium会话 self.driver = webdriver.Remote(appium_server_url, options=options) # 设置一个隐式等待,为所有find_element操作设置一个最大等待时间(后备方案) self.driver.implicitly_wait(10) def tearDown(self): """清理,退出会话""" if self.driver: self.driver.quit() def test_open_battery_settings(self): """测试打开电池设置""" # 方法一:通过文本内容定位(XPath) # 查找文本为“电池”的元素。注意:不同系统语言下文本不同。 battery_item = self.driver.find_element( by=AppiumBy.XPATH, value=‘//android.widget.TextView[@text=“电池”]‘ ) battery_item.click() # 添加一个短暂等待,方便肉眼观察 time.sleep(2) # 简单的验证:判断当前页面是否包含电池相关的元素(例如“电池用量”) # 这里只是示例,实际断言应根据具体页面元素设计 try: self.driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, ‘new UiSelector().textContains(“用量”)‘) print(“成功进入电池设置页面“) except: print(“可能未正确进入电池页面“) # 我们可以再返回上一级菜单,演示TouchAction(触摸动作) # 通常可以按返回键,但这里演示一个不依赖具体元素的滑动操作(假设在屏幕左侧边缘向右滑动可返回) actions = TouchAction(self.driver) start_x = 100 # 起始点X坐标 start_y = self.driver.get_window_size()[‘height‘] // 2 # 屏幕高度中点 end_x = self.driver.get_window_size()[‘width‘] - 100 # 终点X坐标 actions.press(x=start_x, y=start_y).wait(500).move_to(x=end_x, y=start_y).release().perform() time.sleep(1) if __name__ == ‘__main__‘: unittest.main()

脚本解读与技巧

  • 设备连接:确保device_nameadb devices列出的设备一致。如果是模拟器,名字通常是emulator-5554
  • 定位策略:这里使用了XPath通过文本定位。但在实际项目中,如果应用支持,优先让开发同学为关键元素添加accessibility id(在Android是contentDescription,在iOS是accessibilityIdentifier),这是最稳定的定位方式。
  • 隐式等待 vs 显式等待implicitly_wait(10)设置了一个全局的等待时间,在查找任何元素时,如果没立刻找到,会最多等待10秒。但它只对find_element系列方法有效。显式等待(WebDriverWait)更灵活强大,建议复杂场景以显式等待为主,隐式等待作为兜底。
  • TouchAction:用于模拟复杂的触摸手势,如滑动、长按、多点触控等。坐标计算需要获取屏幕尺寸driver.get_window_size()

5. 构建健壮框架:Page Object模式与高级技巧

写几个简单的脚本不难,但当测试用例成百上千时,如何维护?直接在各种测试方法里硬编码定位符和操作,会导致代码极度冗余,UI一变,改起来就是灾难。这就需要引入设计模式,最经典的就是Page Object(PO)模式

5.1 Page Object模式:将页面抽象成对象

PO模式的核心思想是,将一个Web页面或App屏幕抽象成一个Python类。这个类包含:

  • 元素定位器:将页面上需要操作的元素定位方式定义为类的属性。
  • 页面操作方法:将对元素的操作(点击、输入等)封装成类的方法。

这样,测试脚本(TestCase)里就不再出现具体的定位符(如XPath),而是调用页面对象的方法,使得测试逻辑清晰,且页面元素变更只需修改对应的Page类即可。

示例:将百度搜索页面抽象成Page Object

# base_page.py - 所有页面对象的基类,封装一些通用操作 from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC class BasePage: def __init__(self, driver): self.driver = driver self.wait = WebDriverWait(driver, 10) def find_element(self, *locator): """查找单个元素""" return self.wait.until(EC.presence_of_element_located(locator)) def find_clickable_element(self, *locator): """查找可点击元素""" return self.wait.until(EC.element_to_be_clickable(locator)) # baidu_home_page.py - 百度首页的Page Object from selenium.webdriver.common.by import By from base_page import BasePage class BaiduHomePage(BasePage): # 页面元素定位器 SEARCH_INPUT = (By.ID, ‘kw‘) SEARCH_BUTTON = (By.ID, ‘su‘) def input_search_keyword(self, keyword): """在搜索框输入关键词""" search_box = self.find_element(*self.SEARCH_INPUT) # 解包元组 search_box.clear() search_box.send_keys(keyword) def click_search_button(self): """点击搜索按钮""" search_button = self.find_clickable_element(*self.SEARCH_BUTTON) search_button.click() # 在测试脚本中使用 class TestBaiduSearchPO(unittest.TestCase): def setUp(self): service = Service(ChromeDriverManager().install()) self.driver = webdriver.Chrome(service=service) self.driver.get(“https://www.baidu.com“) self.baidu_page = BaiduHomePage(self.driver) # 初始化页面对象 def test_search(self): self.baidu_page.input_search_keyword(“Page Object模式“) self.baidu_page.click_search_button() # ... 后续可以创建SearchResultPage来继续操作

可以看到,测试用例变得非常简洁和易读。如果百度搜索框的ID某天变了,我们只需要去修改BaiduHomePage类中的SEARCH_INPUT定位器即可,所有用到这个搜索框的测试用例都无需改动。

5.2 数据驱动与参数化

同一个测试流程,经常需要用不同的数据来验证。比如登录功能,需要测试正确用户名密码、错误密码、空用户名等多种情况。硬编码多遍测试逻辑是低效的。我们可以使用unittest@parameterized.expand装饰器(需要安装parameterized库)或pytest@pytest.mark.parametrize来实现数据驱动。

使用parameterized示例

import unittest from parameterized import parameterized class TestLogin(unittest.TestCase): @parameterized.expand([ (“正确登录“, “valid_user“, “valid_pass“, True), (“错误密码“, “valid_user“, “wrong_pass“, False), (“空用户名“, ““, “some_pass“, False), ]) def test_login(self, name, username, password, expected_success): # 这里的name是用例描述,会显示在测试报告中 print(f“执行用例:{name}, 用户名:{username}“) # 调用页面对象的登录方法 # login_page.login(username, password) # 断言登录结果是否符合预期 # self.assertEqual(login_page.is_login_success(), expected_success) # 此处为示例,省略具体实现 pass

这样,一个测试方法就变成了三个独立的测试用例,测试报告也会更清晰。

5.3 测试报告与日志

自动化测试跑完了,结果怎么看?我们需要清晰的报告。unittest自带文本报告,但不够直观。可以使用HTMLTestRunner(一个第三方库)来生成漂亮的HTML报告。

生成HTML测试报告示例

import unittest import HtmlTestRunner # ... 你的测试用例类定义 ... if __name__ == ‘__main__‘: # 创建一个测试套件 suite = unittest.TestLoader().loadTestsFromTestCase(TestBaiduSearchPO) # 使用HtmlTestRunner运行并生成报告 runner = HtmlTestRunner.HTMLTestRunner( output=‘reports‘, # 报告输出目录 report_title=‘自动化测试报告‘, descriptions=‘Web自动化测试执行结果‘, report_name=‘MyTestReport‘ ) runner.run(suite)

运行后,会在reports目录下生成一个HTML文件,用浏览器打开,可以看到通过、失败、错误的用例统计,以及每个用例的详细日志,非常便于分析和归档。

此外,在脚本中添加详细的日志记录也至关重要。可以使用Python内置的logging模块,在关键步骤(如开始测试、执行操作、断言、发生异常)记录信息,方便故障排查。

6. 常见问题排查与实战经验锦囊

自动化测试的路上,你会遇到各种各样的“坑”。这里我总结了一些最常见的问题和解决思路,希望能帮你少走弯路。

6.1 元素定位失败:NoSuchElementException

这是最最常见的问题,没有之一。

  • 可能原因1:元素尚未加载出来
    • 解决方案:使用显式等待WebDriverWait),而不是time.sleep或仅用隐式等待。确保等待条件合适(如元素可点击、可见)。
  • 可能原因2:定位器写错了或元素属性已变更
    • 解决方案:使用浏览器开发者工具(F12)或Appium Inspector、UIAutomatorViewer等工具,重新检查元素的属性。确保定位器能唯一标识目标元素。对于Web,尝试用CSS Selector;对于App,优先使用accessibility id
  • 可能原因3:页面存在iframe或原生/WebView上下文切换问题
    • 解决方案(Web):如果元素在iframe里,必须先使用driver.switch_to.frame(frame_reference)切换到对应的iframe中,才能定位其中的元素。操作完后用driver.switch_to.default_content()切回主文档。
    • 解决方案(App):在混合应用(Hybrid App)中,需要在原生(NATIVE_APP)和WebView(WEBVIEW_包名)上下文之间切换。使用driver.contexts获取所有上下文,然后driver.switch_to.context(‘WEBVIEW_xxx‘)进行切换。
  • 可能原因4:动态ID或动态XPath
    • 解决方案:避免使用包含随机数字的ID或绝对XPath。使用相对XPath,结合其他稳定属性(如textclass)进行定位。或者与开发沟通,为测试元素添加固定的测试ID。

6.2 脚本运行速度慢或不稳定

  • 优化等待:减少或避免使用固定的sleep。用显式等待替代,并设置合理的超时时间。对于确实需要固定等待的场景(如等待动画结束),时间也尽量短。
  • 优化定位器:过于复杂的XPath(特别是包含//很多层的)解析效率低。尽量使用ID、CSS Selector等高效定位方式。
  • 网络与环境:确保测试服务器、被测应用服务器网络通畅。在CI/CD环境中,使用专用的、干净的测试机器或容器。
  • 并行执行:对于大量测试用例,考虑使用pytest-xdist等插件进行并行测试,充分利用多核CPU。

6.3 Appium Server连接或会话创建失败

  • 错误:Could not find a connected Android device
    • 检查设备是否通过USB连接且adb devices能列出。
    • 检查是否开启了USB调试模式。
    • 如果是模拟器,确保模拟器已完全启动。
  • 错误:Unable to find an active device or emulator with ...
    • 检查Capabilities中的deviceNameudid是否与adb devices列出的信息匹配。udid的优先级高于deviceName
  • 错误:A new session could not be created
    • 检查Appium Server日志(启动时加--log参数),通常会有更详细的错误信息。常见原因包括:指定的App包名/Activity名不对;设备系统版本与自动化驱动不兼容;端口被占用。

6.4 如何设计可维护的自动化用例

  • 遵循PO模式:这是提高可维护性的第一原则。
  • 用例独立:每个测试用例应该可以独立运行,不依赖于其他用例的执行状态。在setUp中准备测试环境,在tearDown中清理。
  • 使用配置文件:将设备信息、服务器地址、应用包名等配置信息提取到配置文件(如config.iniconfig.yamlconfig.py)中,避免硬编码。
  • 分层设计:将代码分为至少三层:测试用例层(Test Case)、页面对象层(Page Object)、基础工具层(如驱动管理、数据读取、日志配置)。职责清晰,便于复用。
  • 持续集成:将自动化测试脚本接入Jenkins、GitLab CI等持续集成工具,实现代码提交后自动触发测试,并及时反馈结果。

掌握自动化测试,尤其是Python+Selenium+Appium这个组合,是一个从“会用”到“用好”的持续过程。它不仅仅是写脚本,更涉及测试策略、框架设计、持续集成和团队协作。从一个小脚本开始,逐步封装、抽象、完善,最终它会成为你保障产品质量、提升研发效率的得力武器。记住,解决问题的过程,就是你积累经验、提升价值的过程。遇到报错别慌张,仔细看日志,善用搜索,你总能找到答案。