【App 自动化】14 - App 自动化基础与环境

前言

Web 自动化模拟用户在 PC 浏览器上的操作,接口自动化绕过 UI 直接测后端。但还有一类测试没覆盖:用户在手机上的操作

本篇分为两个部分:

第一部分(环境基础):搭建 Appium 测试环境,用 MallLite 移动 Web 版快速验证环境是否可用。这部分不管测移动 Web 还是原生 App,都需要。

第二部分(原生 App 知识体系):原生 App 测试的完整流程、8 种元素定位方式、常用操作(启动/安装/权限弹窗/前后台切换)。这部分是后续 15、16 篇的基础。


一、移动 Web vs 原生 App vs 混合 App

1.1 三种移动端应用类型

复制代码
类型 1:移动 Web
  手机浏览器打开的网页
  技术栈:HTML + CSS + JavaScript
  入口:浏览器地址栏输入 URL
  例子:在手机 Chrome 中打开 MallLite

类型 2:原生 App(后续重点)
  从应用商店下载安装的 App
  技术栈:Android 用 Java/Kotlin,iOS 用 Swift/ObjC
  入口:桌面图标
  例子:微信、淘宝、美团

类型 3:混合 App
  原生 App 的壳 + 内嵌网页(WebView)
  技术栈:原生框架 + WebView 组件
  例子:很多电商 App 的商品详情页其实是一个网页

1.2 三种类型的核心差异

维度 移动 Web 原生 App 混合 App
被测对象 浏览器里的网页 装在手机上的应用 原生壳 + 内嵌网页
安装方式 不需要安装 应用商店/ADB 安装 应用商店/ADB 安装
元素定位 CSS、XPath(跟 PC Web 一样) resource-id、content-desc 两者混合
系统权限 相机、定位、通讯录 部分有
推送通知
离线使用 不支持 支持 部分支持
手势操作 基本滑动 复杂手势(多指、摇一摇) 两者混合

1.3 测试上的区别

复制代码
移动 Web 测试:
  Desired Capabilities → browserName: "Chrome"
  元素定位 → CSS Selector、XPath(跟 PC Web 一样)
  启动方式 → 打开浏览器,输入 URL
  本篇用 MallLite 快速验证

原生 App 测试:
  Desired Capabilities → app: "xxx.apk"(或 app_package + app_activity)
  元素定位 → resource-id、content-desc、accessibility_id
  启动方式 → 启动 App
  后续 15、16 篇重点讲

二、Appium 工作原理

2.1 整体架构

复制代码
你的 Python 测试脚本
    │
    │ ① 发送 HTTP 请求(WebDriver 协议)
    │   例:POST /session/xxx/element/click
    │
    ▼
Appium Server(运行在你的电脑上,端口 4723)
    │
    │ ② 解析命令,转发给对应的 Driver
    │
    ▼
UiAutomator2 Driver(Android 自动化引擎)
    │
    │ ③ 通过 ADB 跟手机通信
    │
    ▼
Android 模拟器 / 真机(执行操作)
    │
    │ ④ 返回结果
    ▼
逐层返回给你的 Python 脚本

知识点:为什么多了一层 Appium Server?

直接通过 ADB 也能控制手机(比如 adb shell input tap 100 200),但这样做有三个问题:

  1. 每个命令都要手动拼 ADB 参数,写起来很繁琐
  2. Android 和 iOS 的命令完全不同,无法统一
  3. 没有元素查找能力(只能用坐标点击,页面一改位置就失效)

Appium Server 的价值是提供统一的 WebDriver 协议,让你用同一套 API 控制不同平台的设备。

2.2 跟 Selenium 的关系

如果你学过 Selenium,Appium 上手会很快,因为两者的协议一样:

复制代码
Selenium:  你的代码 → WebDriver 协议 → ChromeDriver → PC Chrome 浏览器
Appium:    你的代码 → WebDriver 协议 → Appium Server → UiAutomator2 → 手机

代码层面几乎一样:

python 复制代码
# Selenium(PC 浏览器)
from selenium import webdriver
driver = webdriver.Chrome()
driver.get("http://example.com")
driver.find_element(By.ID, "login").click()

# Appium(手机浏览器或 App)
from appium import webdriver
driver = webdriver.Remote("http://localhost:4723", options=...)
driver.get("http://example.com")
driver.find_element(AppiumBy.ID, "login").click()

区别只在:Selenium 的 Driver 是本地的(ChromeDriver),Appium 的 Driver 是远程的(通过 HTTP 连接 Appium Server)。


三、环境搭建

3.1 总览

工具 在哪安装 作用
Java JDK 独立下载 Android SDK 依赖
Android SDK Android Studio(自带) ADB + 模拟器
Node.js 独立下载 Appium Server 依赖
Appium Server 系统终端,用 npm 安装 自动化中转站
Appium Inspector 独立下载 元素查看器
Appium-Python-Client PyCharm 终端,用 pip 安装 Python 调用 Appium

知识点:各工具之间的依赖关系

复制代码
你的 Python 测试脚本
  ↓ import
Appium-Python-Client(Python 库,pip 安装)
  ↓ HTTP 请求
Appium Server(独立服务,npm 安装)
  ↓ 依赖
Node.js(运行时环境)
UiAutomator2 Driver(Appium 驱动)
  ↓ 通过
Android SDK + ADB(调试桥)
  ↓ 依赖
Java JDK(运行时环境)
  ↓ 控制
Android 模拟器 / 真机

3.2 安装步骤

第 1 步:安装 Java JDK

在系统 PowerShell 中执行(不是 PyCharm 终端):

powershell 复制代码
scoop install openjdk17

或者手动下载:浏览器打开 https://adoptium.net/,下载 JDK 17 安装包,双击安装。

验证:

powershell 复制代码
java -version

第 2 步:安装 Android Studio(含 SDK 和模拟器)

复制代码
1. 浏览器打开 https://developer.android.com/studio
2. 下载安装包,双击安装
3. 安装过程中会自动下载 Android SDK
4. 安装完成后打开 Android Studio
5. Tools → Device Manager → Create Device
6. 选择 Pixel 6 → Next
7. 选择 API 34 (Android 14) → Next → Finish

设置环境变量(在 Windows 系统设置中):

复制代码
系统变量新增:
  ANDROID_HOME = C:\Users\你的用户名\AppData\Local\Android\Sdk

Path 中追加:
  %ANDROID_HOME%\platform-tools
  %ANDROID_HOME%\emulator

验证:重新打开 PowerShell,执行:

powershell 复制代码
adb version

第 3 步:安装 Node.js

浏览器打开 https://nodejs.org/,下载 LTS 版本,双击安装。

验证:

powershell 复制代码
node -v
npm -v

第 4 步:安装 Appium Server 和驱动

在系统 PowerShell 中执行:

powershell 复制代码
npm install -g appium
appium driver install uiautomator2

验证:

powershell 复制代码
appium --version

第 5 步:安装 Appium Inspector

浏览器打开 https://github.com/appium/appium-inspector/releases,下载 .exe 安装包,双击安装。

第 6 步:安装 Appium Python Client

在 PyCharm 终端中执行(跟安装 requests、pytest 一样):

powershell 复制代码
pip install Appium-Python-Client

3.3 安装顺序总结

复制代码
第 1 步:系统 PowerShell → scoop install openjdk17
第 2 步:浏览器 → 下载 Android Studio → 安装 → 创建模拟器
第 3 步:浏览器 → 下载 Node.js → 安装
第 4 步:系统 PowerShell → npm install -g appium
第 5 步:系统 PowerShell → appium driver install uiautomator2
第 6 步:浏览器 → 下载 Appium Inspector → 安装
第 7 步:PyCharm 终端 → pip install Appium-Python-Client

前一步失败会影响后面,按顺序来。


四、ADB 常用命令

4.1 什么是 ADB

ADB(Android Debug Bridge)是 Android SDK 提供的命令行工具,用来控制 Android 设备或模拟器。

知识点:ADB 在 App 自动化中的三个用途

用途 场景 命令
找 App 信息 原生 App 测试需要包名和 Activity adb shell dumpsys activity
截图排查 用例失败时截图看当时屏幕状态 adb shell screencap
安装卸载 原生 App 需要先安装 APK adb install / adb uninstall

4.2 设备管理

powershell 复制代码
# 查看连接的设备
adb devices
# 输出:
# List of devices attached
# emulator-5554   device        ← 模拟器
# 192.168.1.100:5555  device    ← WiFi 连接的真机

# 启动模拟器
emulator -avd Pixel_6_API_34

4.3 应用管理

powershell 复制代码
# 安装 APK(原生 App 测试必须)
adb install path/to/app.apk

# 卸载 App
adb uninstall com.example.app

# 查看当前运行的 App(找包名和 Activity)
adb shell dumpsys activity activities | findstr mResumedActivity
# 输出示例:
# mResumedActivity: ActivityRecord{xxx com.example.app/.MainActivity u0}
#                    包名: com.example.app    Activity: .MainActivity

知识点:找包名和 Activity 是原生 App 测试的第一步

原生 App 测试的 Desired Capabilities 需要填 app_packageapp_activity。获取方式:

复制代码
方式 1:打开你想测的 App,然后执行
  adb shell dumpsys activity activities | findstr mResumedActivity

方式 2:如果知道 APK 文件,用 aapt 工具查看
  aapt dump badging app.apk | findstr package
  aapt dump badging app.apk | findstr launchable-activity

方式 3:问开发同学要

4.4 截图和文件

powershell 复制代码
# 截图并保存到电脑
adb shell screencap /sdcard/screenshot.png
adb pull /sdcard/screenshot.png .

# 录屏(Ctrl+C 停止)
adb shell screenrecord /sdcard/record.mp4
adb pull /sdcard/record.mp4 .

# 推送文件到手机
adb push local_file.txt /sdcard/

# 从手机拉取文件
adb pull /sdcard/file.txt .

4.5 设备信息

powershell 复制代码
# 设备型号
adb shell getprop ro.product.model

# Android 版本
adb shell getprop ro.build.version.release

# 屏幕分辨率
adb shell wm size

4.6 日志查看

powershell 复制代码
# 实时查看手机所有日志
adb logcat

# 只看特定关键词
adb logcat | findstr chrome

# 清除日志
adb logcat -c

五、模拟器 vs 真机

维度 模拟器 真机
成本 免费 需要购买
速度 取决于电脑性能 取决于手机性能
稳定性 稳定 可能被电话、通知打断
操作调试 鼠标操作,方便 手指操作
网络访问电脑 10.0.2.2 电脑局域网 IP
覆盖度 一种设备配置 不同品牌、型号
GPS/相机/传感器 需要模拟 真实硬件
适合场景 开发调试、CI/CD 兼容性测试、验收测试

知识点:模拟器中 localhost 不是你的电脑

复制代码
模拟器运行在独立的虚拟网络中:
  localhost 在模拟器中 = 模拟器自己(不是你的电脑)

正确的访问方式:
  Android 官方模拟器:http://10.0.2.2:8000    ← 特殊地址,指向宿主机
  Genymotion 模拟器: http://10.0.3.2:8000
  真机(同一 WiFi): http://电脑局域网IP:8000  ← 如 192.168.1.100:8000

查找电脑局域网 IP:

powershell 复制代码
ipconfig
# 找到 "无线局域网适配器 WLAN" 或 "以太网"
# IPv4 地址:192.168.1.xxx

六、Appium Inspector

6.1 它是什么

Appium Inspector 是一个桌面工具,用来查看手机屏幕上的元素及其属性。类似 PC 浏览器的 F12 开发者工具,只不过是给手机用的。

6.2 启动流程

复制代码
第 1 步:启动 Appium Server
  系统 PowerShell → 执行 appium

第 2 步:启动模拟器
  Android Studio → Device Manager → 启动
  或:emulator -avd Pixel_6_API_34

第 3 步:打开 Appium Inspector
  双击桌面图标

6.3 两种模式的配置

移动 Web 模式(快速验证用):

json 复制代码
{
  "platformName": "Android",
  "appium:automationName": "UiAutomator2",
  "appium:browserName": "Chrome",
  "appium:noReset": true
}

原生 App 模式(后续篇会用):

json 复制代码
{
  "platformName": "Android",
  "appium:automationName": "UiAutomator2",
  "appium:appPackage": "com.example.app",
  "appium:appActivity": ".MainActivity",
  "appium:noReset": false
}

知识点:browserName 和 appPackage 二选一

填了什么 Appium 的行为
browserName: Chrome 打开浏览器 → 移动 Web 模式
appPackage + appActivity 启动 App → 原生 App 模式
两个都填 行为不确定,不要这么做

6.4 使用方式

连接成功后,左侧面板显示元素树,右侧面板显示属性。操作方式:

功能 说明
点击元素树中的节点 右侧显示该元素的属性
Tap 按钮 在手机上模拟点击选中的元素
Swipe 按钮 模拟滑动
地址栏输入 URL 导航到指定网页(移动 Web 模式)
刷新按钮 刷新元素树(页面变化后需要刷新)

七、Desired Capabilities 详解

7.1 什么是 Desired Capabilities

Desired Capabilities 是一组键值对,告诉 Appium Server 你想控制什么样的设备。可以理解为"设备配置清单"。

知识点:为什么叫"Desired"(期望的)?

因为你描述的是你"期望"的设备环境。如果实际设备不满足这些条件,Appium 会报错。比如你期望 platformVersion: 14,但设备是 Android 12,Appium 会提示版本不匹配。

7.2 通用 Capabilities

python 复制代码
options = UiAutomator2Options()

# ===== 平台信息 =====
options.platform_name = "Android"             # 必填,操作系统
options.platform_version = "14"               # 可选,Android 版本(不填自动检测)
options.device_name = "Pixel_6"               # 可选,设备名(不填用第一个连接的设备)
options.automation_name = "UiAutomator2"      # 推荐,自动化引擎

# ===== 会话控制 =====
options.no_reset = True                       # 不重置 App 状态(保留登录态等)
options.full_reset = False                    # 不完全重置(不卸载 App)
options.new_command_timeout = 300             # 无操作超时(秒),默认 60

7.3 移动 Web 专用 Capabilities

python 复制代码
options.browser_name = "Chrome"               # 必填,使用浏览器
# 不填 app 相关参数

7.4 原生 App 专用 Capabilities

python 复制代码
# 方式 1:指定 APK 文件(Appium 会自动安装到设备上)
options.app = "/path/to/app.apk"

# 方式 2:指定包名和 Activity(App 已经装在设备上了)
options.app_package = "com.example.app"
options.app_activity = ".MainActivity"

# 方式 3:两个都填(指定 APK,同时指定启动哪个 Activity)
options.app = "/path/to/app.apk"
options.app_package = "com.example.app"
options.app_activity = ".MainActivity"

7.5 什么时候需要改 Capabilities

场景 改什么
测试移动 Web browser_name = "Chrome",不填 app
测试原生 App app_package + app_activity,不填 browser_name
测试不同 Android 版本 platform_version
用例中途超时断开 new_command_timeout 调大
要清浏览器缓存 no_reset = False
连接真机 device_name 填真机名称

八、原生 App 测试流程

从本节开始进入原生 App 的知识体系。后续 15、16 篇会基于这些知识搭建框架和编写用例。

8.1 原生 App 测试的完整流程

复制代码
第 1 步:获取 App 信息
  拿到 APK 文件,或获取包名和 Activity
  用 ADB 命令或问开发同学

第 2 步:安装 App 到设备
  adb install app.apk
  或在 Capabilities 中填 app 路径让 Appium 自动安装

第 3 步:配置 Desired Capabilities
  填 app_package 和 app_activity(或 app 路径)

第 4 步:用 Appium Inspector 定位元素
  打开 App,找到你需要操作的元素的属性
  记录 resource-id、content-desc、XPath 等

第 5 步:编写测试脚本
  用第 4 步记录的属性编写 Python 代码

第 6 步:运行和调试
  pytest 运行,失败时用 ADB 截图和日志排查

第 7 步:持续集成
  把脚本集成到 CI/CD 流程中

知识点:原生 App 测试比移动 Web 多了哪些步骤?

步骤 移动 Web 原生 App
获取 App 信息 不需要(直接输入 URL) 需要包名和 Activity
安装 App 不需要 需要安装 APK
元素定位 CSS/XPath(跟 PC 一样) resource-id/content-desc(完全不同)
权限处理 不涉及 需要处理系统权限弹窗
前后台切换 不涉及 可能被电话/通知打断

九、原生 App 元素定位方式

9.1 移动 Web vs 原生 App 的定位方式对比

复制代码
移动 Web(跟 PC Web 一样):
  CSS Selector  →  driver.find_element(AppiumBy.CSS_SELECTOR, "#login-btn")
  XPath         →  driver.find_element(AppiumBy.XPATH, "//a[@class='product']")
  TAG_NAME      →  driver.find_element(AppiumBy.TAG_NAME, "a")

原生 App(完全不同的体系):
  ID            →  driver.find_element(AppiumBy.ID, "com.app:id/btn_login")
  ACCESSIBILITY_ID → driver.find_element(AppiumBy.ACCESSIBILITY_ID, "登录")
  CLASS_NAME    →  driver.find_element(AppiumBy.CLASS_NAME, "android.widget.Button")
  ANDROID_UIAUTOMATOR → driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, '...')

9.2 8 种定位方式详解

以一个虚构的电商 App 登录页面为例,讲解每种定位方式:

xml 复制代码
<!-- 登录页面的元素结构(简化版) -->
<LinearLayout>
  <EditText resource-id="com.malllite.app:id/et_username" 
            text="" hint="请输入用户名" class="android.widget.EditText" />
  <EditText resource-id="com.malllite.app:id/et_password" 
            text="" hint="请输入密码" class="android.widget.EditText" />
  <Button   resource-id="com.malllite.app:id/btn_login" 
            text="登录" content-desc="登录按钮" class="android.widget.Button" />
  <TextView resource-id="com.malllite.app:id/tv_register" 
            text="还没有账号?立即注册" content-desc="注册链接" class="android.widget.TextView" />
</LinearLayout>

方式 1:resource-id(最常用)

python 复制代码
# resource-id 是原生 App 元素的唯一标识符(类似 HTML 的 id 属性)
# 格式:包名:resource-id/资源名
driver.find_element(AppiumBy.ID, "com.malllite.app:id/btn_login").click()
driver.find_element(AppiumBy.ID, "com.malllite.app:id/et_username").send_keys("admin")

知识点:resource-id 是原生 App 定位的首选

跟 HTML 的 id 一样,resource-id 通常是唯一的,定位速度快、稳定性好。优先用这个。

方式 2:text

python 复制代码
# 用元素的 text 属性定位
# 注意:text 是精确匹配,不是模糊匹配
driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, 'new UiSelector().text("登录")').click()

知识点:Appium 没有直接的 AppiumBy.TEXT

text 定位需要用 ANDROID_UIAUTOMATOR 引擎,这是 Android 特有的定位方式。写法比较特殊:

python 复制代码
# 包含文本
'driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, \'new UiSelector().textContains("登录")\')'

# 以文本开头
'driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, \'new UiSelector().textStartsWith("还没有")\')'

# 文本匹配正则表达式
'driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, \'new UiSelector().textMatches(".*注册.*")\')'

方式 3:content-desc / accessibility_id

python 复制代码
# content-desc 是无障碍描述(类似 HTML 的 aria-label)
# 用 AppiumBy.ACCESSIBILITY_ID 定位
driver.find_element(AppiumBy.ACCESSIBILITY_ID, "登录按钮").click()
driver.find_element(AppiumBy.ACCESSIBILITY_ID, "注册链接").click()

知识点:content-desc 是什么?

Android 的无障碍服务(如 TalkBack 朗读屏幕内容)会读出 content-desc 的值。开发应该给每个可交互元素设置有意义的 content-desc。它不是必填的,有些元素可能没有。

方式 4:class_name

python 复制代码
# 用 Android 类名定位
# 常见类名:
#   android.widget.Button    → 按钮
#   android.widget.EditText  → 输入框
#   android.widget.TextView  → 文本
#   android.widget.ImageView → 图片
#   android.widget.ListView  → 列表

# 通常不单独用(同类型元素太多),配合其他条件
buttons = driver.find_elements(AppiumBy.CLASS_NAME, "android.widget.Button")

方式 5:xpath

python 复制代码
# XPath 跟 PC Web 的思路一样,但语法不同
# 原生 App 的 XPath 用 Android 类名代替 HTML 标签名

# 找第一个 Button
driver.find_element(AppiumBy.XPATH, "//android.widget.Button")

# 找 text="登录" 的 Button
driver.find_element(AppiumBy.XPATH, '//android.widget.Button[@text="登录"]')

# 找 resource-id 包含 "login" 的元素
driver.find_element(AppiumBy.XPATH, '//*[contains(@resource-id, "login")]')

知识点:XPath 是"最后手段"

XPath 定位慢、容易受页面结构变化影响。优先用 resource-id 和 content-desc,实在找不到再用 XPath。

方式 6:android_uiautomator

python 复制代码
# UiAutomator 是 Android 原生的 UI 测试框架
# Appium 底层就是用它来操作 Android 的
# 可以直接写 UiAutomator 的查找表达式

# 按 resource-id 查找
driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, 
    'new UiSelector().resourceId("com.malllite.app:id/btn_login")')

# 按 class + text 组合查找
driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, 
    'new UiSelector().className("android.widget.Button").text("登录")')

# 按条件组合(AND)
driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, 
    'new UiSelector().resourceId("com.malllite.app:id/btn_login").enabled(true)')

# 在子元素中查找
driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, 
    'new UiScrollable(new UiSelector().scrollable(true)).scrollIntoView(new UiSelector().text("查看更多"))')

知识点:UiAutomator 表达式是 Android 独有的

这是 Android 测试中最强的定位方式,支持各种条件组合和滚动查找。写法复杂,但在其他方式找不到元素时非常有用。

方式 7:android_data_matcher / android_view_matcher(Espresso 引擎)

python 复制代码
# Espresso 是 Google 官方的 Android UI 测试框架
# 如果 automationName 设为 "Espresso"(不是 UiAutomator2),可以用这种方式
# 实际项目中较少使用,了解即可

方式 8:css_selector(仅限 WebView)

python 复制代码
# 只在混合 App 的 WebView 部分有效
# WebView 内嵌的是网页,所以可以用 CSS 定位
# 原生部分不能用
driver.find_element(AppiumBy.CSS_SELECTOR, "#login-btn")

9.3 定位方式选择优先级

复制代码
第 1 选择:resource-id        → 唯一、稳定、快
第 2 选择:content-desc       → 语义清晰、无障碍友好
第 3 选择:text(UiSelector) → 简单直观,但可能有重复
第 4 选择:class + 条件组合   → 需要用 UiAutomator 表达式
第 5 选择:xpath              → 最灵活但最慢,最后手段
仅 WebView:css_selector     → 只在混合 App 的网页部分有效

十、原生 App 常用操作

10.1 启动和安装

python 复制代码
# 方式 1:在 Capabilities 中指定 APK,Appium 自动安装并启动
options.app = "/path/to/app.apk"

# 方式 2:App 已经装在设备上,通过包名启动
options.app_package = "com.malllite.app"
options.app_activity = ".MainActivity"

# 方式 3:通过 ADB 安装(不在 Capabilities 中填 app)
# adb install app.apk
# 然后在 Capabilities 中填 app_package 和 app_activity

# 方式 4:通过 ADB 启动(手动控制启动时机)
# adb shell am start -n com.malllite.app/.MainActivity

10.2 处理系统权限弹窗

Android 系统会在 App 首次使用某些功能时弹出权限请求(如相机、定位、存储)。

python 复制代码
# 方式 1:在 Capabilities 中自动授予所有权限
options.auto_grant_permissions = True

# 方式 2:代码中处理弹窗
try:
    # 查找"允许"按钮并点击
    allow_btn = driver.find_element(AppiumBy.ID, "com.android.permissioncontroller:id/permission_allow_button")
    allow_btn.click()
except:
    # 没有弹窗,继续
    pass

# 方式 3:用 ADB 授予权限(启动 App 之前执行)
# adb shell pm grant com.malllite.app android.permission.CAMERA
# adb shell pm grant com.malllite.app android.permission.ACCESS_FINE_LOCATION

知识点:权限弹窗是原生 App 测试中最常见的"干扰"

如果没有处理权限弹窗,用例会在弹窗处卡住直到超时。推荐在 Capabilities 中设置 auto_grant_permissions = True,让 Appium 自动处理。

10.3 前后台切换

python 复制代码
# 将 App 放到后台(模拟用户按 Home 键)
driver.background_app(5)   # 后台 5 秒后自动回到前台

# 将 App 放到后台(不自动回来)
driver.background_app(-1)  # -1 表示不自动回来

# 手动回到前台
driver.activate_app("com.malllite.app")

知识点:为什么要测前后台切换?

用户在使用 App 时可能被电话、微信通知、系统提醒打断,App 被切到后台。恢复前台后,App 的状态应该正确(不崩溃、不丢失数据、页面状态保持)。

10.4 安装和卸载

python 复制代码
# 检查 App 是否已安装
is_installed = driver.is_app_installed("com.malllite.app")

# 安装 App
driver.install_app("/path/to/app.apk")

# 卸载 App
driver.remove_app("com.malllite.app")

10.5 获取设备信息

python 复制代码
# 获取设备信息
info = driver.capabilities
print(info['platformName'])    # Android
print(info['deviceName'])      # Pixel_6

# 获取当前 Activity
current = driver.current_activity
print(current)  # .MainActivity

10.6 获取页面源码

python 复制代码
# 获取当前页面的 XML 源码(类似查看 HTML 源码)
# 原生 App 的页面结构是 XML 格式
source = driver.page_source
print(source)

知识点:什么时候用 page_source?

当 Appium Inspector 定位不到某个元素时,可以通过 page_source 获取完整的页面 XML 结构,在 XML 文本中搜索元素的属性。这是一个很有用的调试手段。


十一、快速验证:移动 Web 测试脚本

本节用 MallLite 移动 Web 版快速验证环境是否正确。只写 2 条用例,重点是验证环境,不是测业务。

11.1 项目结构

powershell 复制代码
# 在 PyCharm 终端中执行
New-Item -ItemType Directory -Path "app\test_cases" -Force
New-Item -ItemType Directory -Path "app\reports" -Force
New-Item -ItemType File -Path "app\test_cases\__init__.py" -Force
复制代码
app/
├── conftest.py
├── pytest.ini
├── requirements.txt
├── test_cases/
│   ├── __init__.py
│   └── test_mobile_web.py
└── reports/

11.2 pytest.ini

【新建文件】 app/pytest.ini

ini 复制代码
[pytest]
testpaths = test_cases
addopts = -v --tb=short

log_cli = true
log_cli_level = INFO
log_cli_format = %(asctime)s | %(levelname)-8s | %(name)-12s | %(message)s
log_cli_date_format = %H:%M:%S

11.3 requirements.txt

【新建文件】 app/requirements.txt

复制代码
Appium-Python-Client>=4.0.0
pytest>=8.0.0

11.4 conftest.py

【新建文件】 app/conftest.py

python 复制代码
"""
App 自动化 - conftest.py

管理 WebDriver 的创建和销毁
"""

import pytest
from appium import webdriver
from appium.options.android import UiAutomator2Options


@pytest.fixture
def driver():
    """
    创建 Appium WebDriver(连接手机 Chrome)

    生命周期:每个用例创建一个,用例结束后关闭
    """
    options = UiAutomator2Options()
    options.platform_name = "Android"
    options.browser_name = "Chrome"
    options.no_reset = True

    appium_server = "http://localhost:4723"

    driver = webdriver.Remote(appium_server, options=options)
    driver.implicitly_wait(10)

    yield driver

    driver.quit()


@pytest.fixture
def malllite_url():
    """
    MallLite 的 URL(模拟器用 10.0.2.2 访问宿主机)
    """
    return "http://10.0.2.2:8000"

11.5 测试用例

【新建文件】 app/test_cases/test_mobile_web.py

python 复制代码
"""
移动 Web 快速验证(验证环境是否可用)

只写 2 条用例,目的是验证环境搭建是否成功。
详细的内容留给后续篇。
"""

import time
import pytest
from appium.webdriver.common.appiumby import AppiumBy


class TestMobileWebEnvCheck:
    """环境验证"""

    def test_page_loads(self, driver, malllite_url):
        """
        验证 1:MallLite 页面能正常加载

        打开 MallLite 首页,验证页面有内容。
        如果这条通过,说明 Appium + 模拟器 + Chrome + 网络全部正常。
        """
        driver.get(malllite_url)

        # 获取页面标题
        title = driver.title
        assert title is not None, "页面标题为空,可能加载失败"

        # 获取页面内容
        body = driver.find_element(AppiumBy.TAG_NAME, "body")
        body_text = body.text
        assert len(body_text) > 0, "页面内容为空"

        print(f"\n页面标题:{title}")
        print(f"页面内容前 200 字:{body_text[:200]}")

    def test_click_navigates(self, driver, malllite_url):
        """
        验证 2:点击链接能跳转

        找到页面中的第一个链接并点击,验证 URL 发生了变化。
        如果这条通过,说明元素查找和点击操作正常。
        """
        driver.get(malllite_url)

        links = driver.find_elements(AppiumBy.TAG_NAME, "a")

        if len(links) > 0:
            url_before = driver.current_url
            links[0].click()
            time.sleep(2)

            url_after = driver.current_url
            assert url_after is not None
            print(f"\n点击前:{url_before}")
            print(f"点击后:{url_after}")
        else:
            pytest.skip("页面中没有找到链接元素")

11.6 运行

powershell 复制代码
# 终端 1:启动 Appium Server
appium

# 终端 2:启动模拟器(或通过 Android Studio 启动)
emulator -avd Pixel_6_API_34

# 终端 3:启动 MallLite
cd mall-lite
python run.py

# 终端 4:运行测试
cd app
pytest -v

十二、运行验证与问题排查

12.1 环境验证清单

在运行测试之前,逐项检查:

复制代码
□ java -version            → 显示 JDK 版本
□ adb version              → 显示 ADB 版本
□ adb devices              → 显示连接的设备(emulator-xxx)
□ node -v                  → 显示 Node.js 版本
□ appium --version         → 显示 Appium 版本
□ appium driver list       → 显示已安装的驱动(含 uiautomator2)
□ pip show Appium-Python-Client → 显示 Python Client 版本

全部通过后再运行测试。

12.2 常见问题排查

问题 可能原因 解决办法
Connection refused: 4723 Appium Server 没启动 系统终端执行 appium
No device found 模拟器没启动 adb devices 检查
Chrome not found 模拟器没有 Chrome 模拟器中安装 Chrome
页面加载空白 URL 用了 localhost 改成 10.0.2.2
JAVA_HOME not set Java 没装或环境变量没设 重装 Java,设置环境变量
UiAutomator2 not found 没装驱动 appium driver install uiautomator2
Session creation timeout 模拟器卡了 重启模拟器
测试很慢 模拟器性能不足 给模拟器分配更多内存

12.3 用 ADB 截图排查失败

测试失败时,手动截图查看当时的屏幕状态:

powershell 复制代码
adb shell screencap /sdcard/debug.png
adb pull /sdcard/debug.png .
# 打开 debug.png 查看

十三、本篇新增文件

文件 说明
app/pytest.ini App 自动化运行配置
app/conftest.py WebDriver fixture
app/requirements.txt 依赖
app/test_cases/__init__.py 包标记
app/test_cases/test_mobile_web.py 2 条环境验证用例

十四、今日成果

  • 讲解了移动 Web、原生 App、混合 App 三种类型的核心差异
  • 理解了 Appium 的工作原理(Python → Appium Server → Driver → 设备)
  • 搭建了完整的 Appium 测试环境,明确了每个工具在哪安装
  • 掌握了 ADB 常用命令(设备管理、应用管理、截图、文件、日志)
  • 了解了模拟器和真机的优劣对比和网络差异
  • 学会了用 Appium Inspector 定位元素(移动 Web 和原生 App 两种模式)
  • 搞懂了 Desired Capabilities 的每个参数含义
  • 系统学习了原生 App 测试的完整流程(7 步)
  • 掌握了 8 种元素定位方式(resource-id、text、content-desc、class、xpath、uiautomator、espresso、css)及优先级
  • 学会了原生 App 的常用操作(安装、启动、权限弹窗、前后台切换)
  • 用 MallLite 移动 Web 快速验证了环境

十五、下篇预告

15 - App 自动化框架搭建

下一篇搭建完整的原生 App 自动化框架:Driver Manager(管理 Appium 连接)、BasePage(封装滑动/长按/权限弹窗等原生操作)、页面对象实现(登录页/首页/商品页/购物车页)。


App 自动化篇进度:14/18。

相关推荐
新时代牛马1 小时前
Linux 防火墙:nftables 与iptables 兼容层
linux·运维·服务器
xhbh6661 小时前
中小企业 Redis 运维,如何安全归档 RDB、AOF 备份文件?
运维·数据库·缓存·数据备份·文件备份·同步备份·号码备份
是逍遥子没错1 小时前
一个斜杠,击穿整座网关:API网关路径前缀绕过认证实战
运维·服务器·web安全·网络安全·渗透测试·系统安全
其实防守也摸鱼2 小时前
每天一个知识点——RCE漏洞
运维·服务器·数据库·windows·安全·github·漏洞
努力努力再努力wz2 小时前
【Docker 入门系列】:从 Namespace、CGroup 到 LXC:理解容器运行时、rootfs 与 LXC 实战
运维·docker·容器
JavaPub-rodert3 小时前
Docker 多阶段构建:为什么生产环境镜像可以小 90%
运维·docker·容器
2601_962218474 小时前
万象生鲜系统多账套隔离技术适配集团生鲜企业集团化数字化管控
大数据·运维·微服务·云原生·架构
王志来137944730084 小时前
安防监控工控工业服务器配套
运维·服务器·python
星禾元亨4 小时前
企业 AI 落地 5 步路线图:诊断、企业知识库与 GEO 获客的工程化实施步骤
大数据·人工智能·自动化·创业创新