从零构建Appium+MuMu+Python自动化测试环境:实战避坑指南
1. 环境搭建:软件安装与配置
第一次搭建Appium测试环境时,我花了整整两天时间才把所有依赖装好。后来发现,其实只要按顺序安装这几个关键组件就能避免90%的问题。先说说必须安装的软件清单:
- JDK:建议直接安装JDK 8,这是最稳定的版本。安装完成后记得运行
java -version验证,我遇到过因为系统残留旧版本导致环境混乱的情况 - Android SDK:不用完整安装Android Studio,单独下载命令行工具就行。重点是要配置好
ANDROID_HOME环境变量,这个后面会详细说 - Python:推荐3.7+版本,太新的版本可能遇到库兼容性问题。我习惯用pyenv管理多版本Python,避免污染系统环境
- Appium Desktop:图形化界面比命令行版更适合新手。有个坑要注意 - 安装路径不要有中文或空格,否则可能报奇怪的权限错误
- Node.js:Appium的运行依赖Node环境。安装LTS版本即可,装完记得用
npm -v检查是否成功 - MuMu模拟器:网易官方的稳定版就行,别用修改版。安装后先别急着启动,后面有重要配置要做
环境变量是新手最容易栽跟头的地方。我建议这样配置:
- 用户变量里添加
JAVA_HOME,指向JDK安装目录 - 系统Path中添加
%JAVA_HOME%\bin和%ANDROID_HOME%\platform-tools - 新建系统变量
ANDROID_HOME指向SDK目录
验证是否配对了有个妙招 - 新开cmd窗口分别执行adb、java、python这三个命令,如果都能显示帮助信息而不是"不是内部命令",说明基础环境OK了。
2. MuMu模拟器的特殊配置
MuMu模拟器默认用的adb端口是7555,这和标准模拟器不同。我第一次用时死活连不上,后来发现需要做这几个特殊操作:
首先要把MuMu安装目录下的adb.exe复制到Android SDK的platform-tools里替换原文件。这个操作很多人会忽略,结果就是adb devices永远找不到设备。替换后执行:
adb kill-server
adb connect 127.0.0.1:7555
adb devices
应该能看到类似这样的输出:
List of devices attached
127.0.0.1:7555 device
如果显示offline或者空列表,试试这些排查步骤:
- 确保模拟器已经完全启动(看到桌面图标)
- 任务管理器里结束所有adb.exe进程再重试
- 关闭电脑上的手机助手类软件,它们会抢占adb端口
- 在MuMu设置里开启USB调试模式(虽然叫USB调试,但对模拟器也有效)
有个隐藏技巧:MuMu多开时每个实例端口会递增,比如第二个实例是7556。如果要做多设备测试,需要分别连接这些端口。
3. Appium服务配置详解
打开Appium Desktop后别急着点Start Server,先做这些配置能省去后面很多麻烦:
在"Edit Configurations"里,我建议这样设置:
allowCors: true (解决跨域问题)localTimezone: true (避免时区导致的日志时间错乱)webDriverAgentUrl: http://localhost:8100 (iOS测试不用管,Android保持默认)
重点来了 - 必须勾选"Override existing sessions",否则第二次运行脚本时会报session冲突错误。这个坑我踩过三次才找到原因。
启动服务后,控制台出现"Appium REST http interface listener started on 0.0.0.0:4723"才算成功。如果端口被占用,可以在启动参数里换其他端口,但要记得后续Python脚本里的URL也要相应修改。
4. 编写第一个自动化脚本
终于到了写代码环节!先安装Python客户端库:
pip install Appium-Python-Client
这是我调试过的最简可用脚本模板:
from appium import webdriver
desired_caps = {
'platformName': 'Android',
'deviceName': 'MuMu', # 自定义名称
'platformVersion': '6.0.1', # 需与模拟器系统版本一致
'appPackage': 'com.android.settings',
'appActivity': '.Settings',
'automationName': 'uiautomator2',
'noReset': True # 避免每次重置模拟器
}
driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
# 点击WLAN设置
driver.find_element_by_xpath("//*[@text='WLAN']").click()
driver.quit()
几个容易出错的地方:
platformVersion必须和模拟器"关于手机"里的系统版本完全一致,差个小版本号都会报错- 新版本Appium推荐用
uiautomator2而不是老版的UiAutomator1 - 元素定位优先用
resource-id,其次才是text。用Android SDK里的uiautomatorviewer工具查看元素属性最可靠
5. 获取应用包名和Activity
很多教程教人用反编译工具获取包名和主Activity,其实有更简单的方法:
adb shell dumpsys window | find "mCurrentFocus"
运行后会显示类似这样的信息:
mCurrentFocus=Window{xxxxxxx u0 com.xxx.xxx/com.xxx.xxx.MainActivity}
斜杠前面是包名,后面是当前Activity。
对于未安装的应用,可以用aapt工具:
aapt dump badging your_app.apk | find "package: name="
aapt dump badging your_app.apk | find "launchable-activity: name="
6. 常见问题排查指南
问题一:adb devices列表为空
- 解决方案:按顺序执行
adb kill-serveradb start-serveradb connect 127.0.0.1:7555- 检查模拟器设置中的"开发者选项"是否开启
问题二:Appium报错"Unable to find a matching set of capabilities"
- 检查项:
- desired_caps里的键名不能有拼写错误(比如错写成'platform'少了个'Name')
- 确保设备名称和Appium配置一致
- 模拟器系统版本和caps中的platformVersion完全匹配
问题三:元素定位失败
- 优化方案:
- 增加隐式等待
driver.implicitly_wait(10) - 改用显式等待:
from selenium.webdriver.support.ui import WebDriverWait WebDriverWait(driver, 10).until(lambda x: x.find_element_by_id("some_id"))- 在uiautomatorviewer里确认元素是否确实存在
- 增加隐式等待
问题四:截图保存失败
- 正确写法:
import os
os.makedirs('screenshots', exist_ok=True) # 自动创建目录
driver.get_screenshot_as_file(f'screenshots/{datetime.now().strftime("%Y%m%d_%H%M%S")}.png')
7. 实战技巧:处理权限弹窗
国内应用经常在启动时请求各种权限,可以用这段代码自动点击允许:
try:
allow_btn = driver.find_element_by_id("com.android.packageinstaller:id/permission_allow_button")
allow_btn.click()
except:
pass # 如果没有弹窗就跳过
更健壮的写法是循环检测多个可能的权限弹窗:
permission_ids = [
"com.android.packageinstaller:id/permission_allow_button",
"android:id/button1", # 另一种确定按钮
"com.android.permissioncontroller:id/permission_allow_button" # 新版Android
]
for pid in permission_ids:
try:
driver.find_element_by_id(pid).click()
except:
continue
8. 进阶:录制与回放
Appium Inspector的录制功能其实很好用,但要注意:
- 先启动会话再点击"Start Recording"
- 操作完成后别急着关会话,先点击"Copy Code"获取Python代码
- 生成的代码可能需要微调,特别是元素定位部分
我习惯把常用操作封装成函数:
def click_by_text(text):
driver.find_element_by_xpath(f"//*[@text='{text}']").click()
def input_text(resource_id, text):
elem = driver.find_element_by_id(resource_id)
elem.clear()
elem.send_keys(text)
最后提醒一个性能优化点:在desired_caps里加上'skipDeviceInitialization': True可以跳过一些不必要的设备检查,让脚本启动更快。这套环境搭好后,接下来就可以大展拳脚写各种自动化测试用例了。从个人经验看,环境搭建虽然麻烦,但一次配好能省去后续无数调试时间。建议把整个环境打包成虚拟机镜像或者Docker镜像,方便团队共享使用。
更多推荐
所有评论(0)