文章目录
- 移动APP测试
-
- 一、APP的测试点
- 二、功能测试:不值是把页面点一遍
-
- [2.1 四种核心测试设计方法](#2.1 四种核心测试设计方法)
-
- [2.1.1 等价类划分](#2.1.1 等价类划分)
- [2.1.2 边界值分析](#2.1.2 边界值分析)
- [2.1.3 场景法](#2.1.3 场景法)
- [2.1.4 错误推测法](#2.1.4 错误推测法)
- [2.2 登录模块完整用例(示例)](#2.2 登录模块完整用例(示例))
- [2.3 APP功能测试和Web功能测试的核心区别](#2.3 APP功能测试和Web功能测试的核心区别)
- [2.4 APP测试和小程序测试的核心区别](#2.4 APP测试和小程序测试的核心区别)
- 三、兼容性测试:APP测试最重的板块
-
- [3.1 Android碎片化](#3.1 Android碎片化)
- [3.2 品牌ROM的测试注意事项](#3.2 品牌ROM的测试注意事项)
- [3.3 屏幕适配测试](#3.3 屏幕适配测试)
- [3.4 输入法兼容性](#3.4 输入法兼容性)
- 四、专项测试:APP测试的"独门绝活"
-
- [4.1 弱网测试](#4.1 弱网测试)
- [4.2 中断测试](#4.2 中断测试)
-
- [4.2.1 来电中断](#4.2.1 来电中断)
- [4.2.2 切换后台](#4.2.2 切换后台)
- [4.2.3 系统弹窗和事件](#4.2.3 系统弹窗和事件)
- [4.2.4 Android 返回键 以及 iOS 手势返回](#4.2.4 Android 返回键 以及 iOS 手势返回)
- [4.3 耗电量测试](#4.3 耗电量测试)
- [4.4 流量消耗测试](#4.4 流量消耗测试)
- [4.5 安装 / 卸载 / 升级测试](#4.5 安装 / 卸载 / 升级测试)
- 五、性能测试
-
- [5.1 响应时间基准](#5.1 响应时间基准)
- [5.2 内存测试](#5.2 内存测试)
- [5.3 CPU测试](#5.3 CPU测试)
- [5.4 后端接口压力测试(JMeter)](#5.4 后端接口压力测试(JMeter))
- 六、安全测试
-
- [6.1 数据存储安全](#6.1 数据存储安全)
- [6.2 数据传输安全](#6.2 数据传输安全)
- [6.3 权限与越权](#6.3 权限与越权)
- [6.4 反编译与代码安全](#6.4 反编译与代码安全)
- 七、UI自动化测试
-
- [7.1 Appium:跨平台UI自动化](#7.1 Appium:跨平台UI自动化)
- [7.2 元素定位方式](#7.2 元素定位方式)
- [7.3 Page Object 模式](#7.3 Page Object 模式)
- 八、APP测试检查清单
移动APP测试
一、APP的测试点
做APP测试最容易犯的错就是只测功能------把页面点一遍没崩就觉得测完了。但实际上功能测试只占APP测试工作量的50%左右,另一半是各种专项测试。
APP测试全景
│
├── 功能测试(50%)
│ ├── 正向流程:正常用户操作路径
│ ├── 异常流程:错误输入、异常操作
│ ├── 边界值:输入极限值
│ └── 权限:首次授予、拒绝、二次触发
│
├── 兼容性测试(15%)
│ ├── 系统版本:Android 10-15、iOS 15-18
│ ├── 手机品牌:华为/小米/OPPO/vivo/三星
│ ├── 屏幕尺寸:小屏/主流/大屏/折叠屏
│ └── 网络环境:WiFi/4G/5G/弱网
│
├── 专项测试(20%)
│ ├── 弱网测试:2G/3G/4G/弱WiFi/断网/网络切换
│ ├── 中断测试:来电/短信/闹钟/锁屏/低电量/后台
│ ├── 耗电测试:后台播放/持续定位/高频网络请求
│ ├── 流量测试:首次启动/页面浏览/流媒体播放
│ └── 安装升级测试:首次安装/覆盖/升级/降级/卸载重装
│
├── 性能测试(10%)
│ ├── 响应时间:冷启动/热启动/页面切换/接口
│ ├── 内存:内存占用/内存泄漏/低内存回收
│ ├── CPU:空闲/正常/峰值
│ ├── 帧率:滑动流畅度/动画卡顿
│ └── 并发:多用户同时操作的稳定性
│
└── 安全测试(5%)
├── 数据存储:密码/Token/数据库文件
├── 数据传输:HTTPS/证书校验/加密
├── 权限控制:横向越权/纵向越权
└── 反编译:APK/IPA代码安全
二、功能测试:不值是把页面点一遍
2.1 四种核心测试设计方法
2.1.1 等价类划分
案例:手机号输入框
| 等价类 | 代表值 | 是否有效 |
|---|---|---|
| 有效11位,1开头 | 13800138000 | 有效 |
| 有效11位,非1开头(虚拟运营商) | 17012345678 | 有效(取决于产品规则) |
| 少于11位 | 138001 | 无效 |
| 多于11位 | 138001380001 | 无效 |
| 含字母 | 138001abc00 | 无效 |
| 含特殊符号 | 138-0013-8000 | 视产品规则 |
| 空值 | (不输入) | 无效 |
| 已注册手机号 | 已注册的真实号 | 有效(登录场景) |
| 未注册手机号 | 未注册的新号 | 无效(登录场景)/ 有效(注册场景) |
2.1.2 边界值分析
边界是bug的高发地带,取边界值本身和紧邻的两个值。
案例:验证码倒计时60秒
| 时刻 | 操作 | 预期 |
|---|---|---|
| 刚点击"获取验证码" | 立刻再点击 | 按钮置灰,不可点 |
| 第1秒 | 点击 | 不可点 |
| 第59秒 | 点击 | 不可点 |
| 第60秒 | 点击 | 重新变为可点击 |
| 第61秒 | 点击 | 可点 |
同样,输入框的 maxlength=200:用199/200/201个字符各测一次。
2.1.3 场景法
模拟用户从打开APP到完成目标的完整操作路径。
案例:爱听外语"从扫码到完成一篇精听"

用场景法测试时关注:步骤间的数据传递是否一致(比如音频下载后的缓存路径、听写进度的保存和恢复)。
2.1.4 错误推测法
靠经验猜"这个地方最容易出bug"然后针对性验证。常见的直觉测试点:
- 网络切换时提交表单
- 快速连续点击同一个按钮
- 输入内容很多后再删完
- 跨天/跨月的连续操作
- 两个功能同时进行(如下载的同时播放音频)
2.2 登录模块完整用例(示例)
以爱听外语APP登录页面为例,按照功能测试的维度展开:
手机号输入:
| 场景 | 输入 | 预期 |
|---|---|---|
| 正常 | 13800138000 | 格式校验通过 |
| 空值 | (空) | 提示"请输入手机号" |
| 非11位 | 13800 | 提示"请输入正确的手机号" |
| 含字母 | 138001abc00 | 提示"请输入正确的手机号" |
| 含空格 | 138 0013 8000 | 自动过滤空格或提示格式错误 |
| 含emoji | 138001😀8000 | 自动过滤 |
| SQL注入 | ' OR 1=1 -- | 被拦截或视为无效输入 |
获取验证码:
| 场景 | 操作 | 预期 |
|---|---|---|
| 正常发送 | 手机号正确,点获取 | 收到短信,倒计时开始 |
| 60秒内 | 倒计时中再次点击 | 按钮置灰不可点 |
| 重复获取 | 1分钟内同一手机号 | 频率限制,提示稍后再试 |
| 断网 | 无网络时点击 | 提示"网络连接失败" |
| 服务端错误 | 服务端返回500 | 提示"服务异常,请稍后重试" |
| 短信延迟 | 60秒后才收到 | 验证码可能已过期 |
协议勾选:
| 场景 | 操作 | 预期 |
|---|---|---|
| 都不勾 | 直接点登录 | 提示"请先同意用户协议和隐私政策" |
| 只勾一个 | 勾用户协议不勾隐私政策点登录 | 提示或登录按钮不可用 |
| 勾选再取消 | 两个都勾后取消一个 | 登录按钮变回不可用 |
| 点击协议链接 | 点击《用户协议》文字 | 跳转到协议详情页 |
2.3 APP功能测试和Web功能测试的核心区别
| 维度 | APP | Web |
|---|---|---|
| 输入方式 | 软键盘(不同输入法)+ 物理按键 | 物理键盘为主 |
| 手势操作 | 左滑删除/下拉刷新/长按菜单/双击放大 | 鼠标点击/滚轮 |
| 屏幕方向 | 横屏竖屏切换 | 窗口大小调整 |
| 返回行为 | 物理返回键/手势返回(Android)vs 左上角返回(iOS) | 浏览器返回按钮 |
| 多任务 | 分屏/悬浮窗模式 | 多标签页 |
2.4 APP测试和小程序测试的核心区别
| 维度 | 原生APP | 微信小程序 |
|---|---|---|
| 运行环境 | 独立运行在操作系统之上 | 依赖微信客户端(WebView + JsCore 双线程) |
| 安装方式 | 应用商店下载安装(几十MB~几GB) | 无需安装,扫码即用(包体 ≤ 20MB) |
| 系统权限 | 独立申请系统权限,弹窗样式各ROM不同 | 继承微信权限体系,弹窗统一 |
| 兼容矩阵 | 系统版本 × 手机品牌 × 屏幕尺寸 | + 微信版本 × 基础库版本 |
| 发布更新 | 应用商店审核1-3天,用户手动更新 | 审核通过即时生效,用户无感 |
| 后台行为 | 受各ROM后台策略影响(华为激进/原生宽松) | 受微信后台策略统一管控 |
| 页面栈 | 无限制,Activity/Fragment自由管理 | 最多10层,超出后 navigaTo 失效 |
| 包体积 | 无严格限制(通常数百MB) | 主包 ≤ 2MB,总包 ≤ 20MB(含所有分包) |
| 自动化工具 | Appium / UIautomator2 / XCUITest | minium / Airtest / 微信云测 |
| 抓包调试 | Charles/Fiddler 直接抓 | 需额外配置(Android需root或VirtualXposed) |
| 调试工具 | Android Studio / Xcode | 微信开发者工具(模拟器 + 真机调试) |
| 代码安全 | APK可被jadx反编译,IPA可被class-dump解包 | wxapkg可被解包,核心逻辑必须放后端 |
| 支付体系 | 接入各平台支付SDK(支付宝/微信/银联) | 仅支持微信支付,走 wx.requestPayment |
| 缓存上限 | 自由管理空间 | Storage API 上限 10MB |
| 登录方式 | 手机号/第三方/生物识别 | 微信一键登录 + 手机号授权 + 第三方 |
| 测试策略差异 | 专项测试重:弱网/中断/耗电/流量/安装升级 | 专项测试轻(微信托管大部分),但需额外验证包体积和基础库兼容 |
三、兼容性测试:APP测试最重的板块
3.1 Android碎片化
| 兼容维度 | 最小覆盖 | 理想覆盖 |
|---|---|---|
| Android系统版本 | 10/11/12/13/14/15 (6个) | 最小覆盖 + 各版本的不同ROM |
| 手机品牌 | 华为/小米/OPPO/vivo/三星 (5个) | 前5 + 荣耀/一加/realme/中兴 |
| 屏幕分辨率 | 720p/1080p/2K (3个) | 常见DPI组合全覆盖 |
| iOS系统版本 | 15/16/17/18 (4个) | 覆盖所有仍在支持的版本 |
| 屏幕类型 | 直面屏/曲面屏/折叠屏 | 每种形态全覆盖 |
理想情况下兼容性测试量 = 6 × 5 × 3 ≈ 90个环境。实际不可能全手工覆盖,通常策略是:
- 手工测试:覆盖Top 5品牌 × 最新2个系统版本 = 10台真机
- 云测平台:Testin、WeTest等云端覆盖剩余组合
- 灰度发布:先1%用户 → 再10% → 全量
3.2 品牌ROM的测试注意事项
| 品牌 | ROM | 定制深度 | 测试注意点 |
|---|---|---|---|
| 华为 | HarmonyOS/EMUI | 极深 | 后台进程管理极激进,APP易被杀;推送走华为通道 |
| 小米 | HyperOS/MIUI | 深 | 权限弹窗文案和原生不同;省电模式限制后台;小窗模式 |
| OPPO | ColorOS | 深 | 通知权限默认关闭;应用自启动需手动开启 |
| vivo | OriginOS | 深 | 悬浮窗权限逻辑不同;后台弹窗受限 |
| 三星 | OneUI | 中 | 较接近原生Android;折叠屏适配重点机型 |
| 荣耀 | MagicOS | 深 | 与华为分家后推送/权限体系独立 |
| Pixel | 原生Android | 浅 | 作为基准参照 |
测试必须验证的场景:
- APP被系统杀进程后,重新打开的状态(数据是否丢失、登录态是否还在)
- 首次安装时权限弹窗的样式(不同ROM弹窗文案和按钮位置不同)
- 后台播放音频是否受限(华为/小米比较激进,可能在锁屏后几分钟杀掉)
3.3 屏幕适配测试
尺寸分类:
| 类别 | 典型分辨率 | 测试要点 |
|---|---|---|
| 小屏 | 720×1280 (4.7-5.5寸) | 内容是否截断,按钮是否过小无法点击 |
| 主流 | 1080×1920/1080×2400 (6.1-6.7寸) | 首选测试基准 |
| 大屏 | 1440×2560/1440×3200 (6.8寸+) | 字体缩放后是否溢出 |
| 平板 | 2048×1536 等 | 横屏布局是否合理 |
| 折叠屏 | 展开/折叠状态 | 状态切换时布局是否自适应 |
全面屏适配:
| 适配项 | 测试方法 |
|---|---|
| 挖孔/刘海区域 | 查看APP内容是否被遮挡 |
| 底部指示条区域 | 底部按钮是否被虚拟Home指示条遮挡 |
| 全面屏手势 | 侧滑返回手势是否和APP内滑动冲突 |
| 状态栏沉浸 | 顶部状态栏和APP导航栏颜色是否协调 |
3.4 输入法兼容性
不同第三方输入法会影响键盘弹出行为和输入框位置:
| 输入法 | 测试注意 |
|---|---|
| 搜狗输入法 | 市场占有率最高,必测 |
| 百度输入法 | 自定义工具栏可能遮挡输入框 |
| 讯飞输入法 | 语音输入模式切换 |
| 系统自带 | 三星键盘/华为小艺输入法/iOS原生键盘 |
| 第三方键盘(iOS) | iOS 支持第三方键盘但行为可能不一致 |
核心测试点:键盘弹出时页面是否能滚动到输入框可见的位置,键盘收起后页面是否能恢复。
四、专项测试:APP测试的"独门绝活"
4.1 弱网测试
用户在电梯、地铁、地下车库使用APP是常态,弱网下的表现直接影响留存
模拟工具:
- Charles Proxy:Proxy → Throttle Settings → 配置限速参数
- Fiddler:Rules → Performance → Simulate Modem Speeds
- iOS 开发者模式:设置 → 开发者 → Network Link Conditioner
- Android 开发者模式:网络 → 选择网络类型
标准模拟参数:
| 网络类型 | 上行 | 下行 | 延迟 | 丢包率 | 模拟场景 |
|---|---|---|---|---|---|
| 2G(GPRS) | 20kbps | 50kbps | 500ms | 5% | 极限弱信号 |
| 弱3G | 64kbps | 192kbps | 300ms | 3% | 偏远地区 |
| 强3G | 128kbps | 384kbps | 200ms | 1% | 城郊 |
| 4G弱信号 | 1Mbps | 5Mbps | 100ms | 1% | 商场/地铁 |
| 4G强信号 | 10Mbps | 40Mbps | 40ms | 0% | 室外基站附近 |
| 弱WiFi | 256kbps | 512kbps | 300ms | 5% | 远距离WiFi |
| 网络抖动 | 正常 | 正常 | 0-1000ms波动 | 随机3% | 高铁/高速移动 |
| 100%丢包 | --- | --- | --- | 100% | 隧道/电梯 |
每种网络下的验证清单:
页面是否能加载出来(可以慢但不能白屏死等)
Loading状态是否明确展示(不能让用户以为卡死了)
超时后是否给出提示(不能一直转圈)
弱网下重复点击是否产生重复请求
弱网下提交表单是否产生重复数据
弱网切正常网络后是否能自动恢复(不需要用户重试)
音视频播放:缓冲策略是否正确(不是一直加载0%)
网络切换测试:
| 切换场景 | 测试方法 | 验证点 |
|---|---|---|
| WiFi → 4G | 播放中关WiFi | 播放不中断或短暂缓冲后继续 |
| 4G → WiFi | 连上WiFi | 自动切换到更好的网络 |
| 4G → 飞行模式 | 打开飞行模式 | 暂停并提示网络不可用 |
| 飞行模式 → 4G | 关闭飞行模式 | 自动恢复或手动可重试 |
| WiFi→4G切换中提交 | 切换瞬间提交请求 | 请求不丢失,有重试机制 |
4.2 中断测试
APP在运行中会遇到各种系统级中断,每一个都必须验证:
4.2.1 来电中断
| 场景 | APP状态 | 中断后表现 | 恢复后表现 |
|---|---|---|---|
| 登录/注册 | 填写表单中 | 通话界面覆盖APP | 切回后表单数据保留 |
| 下单支付 | 支付中 | APP退到后台 | 切回后查询支付结果 |
| 音视频播放 | 播放中 | 播放自动暂停 | 通话结束后可继续播放或需手动恢复 |
| 下载/上传 | 传输中 | 传输暂停 | 通话结束后自动续传 |
| 游戏/计时 | 计时中 | 计时暂停 | 通话结束后计时继续 |
4.2.2 切换后台
| 测试参数 | 说明 |
|---|---|
| 切后台时长 | 1分钟 / 5分钟 / 30分钟 / 2小时 |
| 切后台前APP状态 | 首页 / 填写表单 / 播放中 / 下单中 |
| 切回后验证 | 状态是否保持 / Token是否过期 / 数据是否同步 |
Android 和 iOS 差异:
- iOS "退到后台"3分钟后 APP 可能被系统冻结(Suspended状态),30分钟后可能被杀
- Android 取决于 ROM 的进程管理策略,华为比原生 Android 激进得多
4.2.3 系统弹窗和事件
| 事件 | 测试方法 | 关键验证 |
|---|---|---|
| 低电量弹窗(20%/10%) | 将手机用到临界电量 | 弹窗不导致APP崩溃 |
| 系统权限弹窗 | 触发权限 + 系统弹窗叠加 | 弹窗顺序正确 |
| 闹钟响起 | 设闹钟 + 使用APP | 闹钟不导致APP卡死 |
| 日历提醒 | 设日程提醒 | 提醒弹窗不阻塞操作 |
| 短信通知 | 发短信给自己 | 顶部通知条不遮挡操作区 |
| 蓝牙连接提示 | 打开关闭蓝牙 | 如有蓝牙依赖功能验证状态变化 |
4.2.4 Android 返回键 以及 iOS 手势返回
| 平台 | 行为 | 测试要点 |
|---|---|---|
| Android | 物理/虚拟返回键 | 首页按返回 → 弹出退出确认或退回桌面 |
| Android | 物理/虚拟返回键 | 非首页 → 返回上一页,行为等同于navigateBack |
| iOS | 左侧边缘右滑 | 仅在支持手势返回的页面生效 |
| iOS | 左上角返回按钮 | 所有子页面必须有,否则用户"卡住" |
4.3 耗电量测试
音频类、视频类、定位类APP尤其需要关注耗电。
测试工具:
| 平台 | 工具 | 用途 |
|---|---|---|
| Android | Battery Historian(Google官方) | 精确到每个APP每个wakeLock的耗电 |
| Android | 开发者选项 → 正在运行的服务 | 简单查看 |
| iOS | Xcode → Debug → Energy Log | 精细耗电分析 |
| iOS | 设置 → 电池 | 按APP查看耗电占比 |
测试场景与指标:
| 场景 | 操作 | 合格标准 |
|---|---|---|
| 后台静置 | APP在后台1小时 | 耗电 < 5% |
| 在线音频播放 | 连续播放1小时 | 耗电 < 15% |
| GPS持续定位 | 持续定位1小时 | 耗电 < 25% |
| 前台无操作 | 亮屏不操作10分钟 | APP 耗电占比 < 5% |
常见的耗电元凶:
| 原因 | 表现 | 排查方法 |
|---|---|---|
| 持有WakeLock | 屏幕关了CPU还在跑 | Battery Historian |
| GPS未及时关闭 | 定位图标一直显示 | 查看状态栏定位图标 |
| 高频轮询 | 每秒请求一次接口 | 抓包看请求频率 |
| 动画未暂停 | 切后台后动画还在跑 | 开发者选项 → GPU呈现模式 |
| 后台音频未释放 | 退出播放后audio仍在 | 查看系统音频焦点 |
4.4 流量消耗测试
用户对流量消耗很敏感,尤其在非WiFi环境的下
测试工具:
| 平台 | 工具 |
|---|---|
| Android | 设置 → 网络和互联网 → 数据使用量(可按APP筛选) |
| iOS | 设置 → 蜂窝网络 → 查看各APP用量 |
| Charles | 统计请求总字节数 |
关键场景的流量基准:
| 场景 | 合格 | 优秀 |
|---|---|---|
| 首次安装冷启动(含必要资源下载) | < 5MB | < 2MB |
| 浏览一个列表页(20条数据) | < 500KB | < 200KB |
| 浏览一个详情页(含图片) | < 1MB | < 300KB |
| 音频流播放 10分钟 | < 15MB | < 10MB |
| 后台1小时(无主动使用) | < 1MB | < 200KB |
流量优化方向:图片懒加载、接口返回数据精简字段、缓存策略(列表数据10分钟内不重复请求)、WIFI下预加载大资源。
4.5 安装 / 卸载 / 升级测试
| 测试场景 | 具体操作 | 验证点 |
|---|---|---|
| 首次安装 | 应用商店下载 → 安装 → 首次打开 | 首次权限弹窗正常;引导页展示;无闪退 |
| 覆盖安装 | 同版本号APK再次安装 | 用户数据不丢失;不出现"安装失败 |
| 升级-数据迁移 | v1.0 → v2.0(数据库表结构变了) | 旧数据正确迁移到新表结构;新功能可用 |
| 升级-旧API兼容 | v1.0 → v2.0(新API替代旧API) | 检查是否仍有接口指向已废弃的旧API |
| 跨版本大升级 | v1.0 → v3.0 | 跨版本升级路径数据完整性 |
| 降级安装(Android) | v2.0 → v1.0 | 应提示"无法降级"或数据回退处理 |
| 卸载 | 卸载APP | APP所有文件被清除(不残留) |
| 卸载重装 | 卸载 → 重新下载安装 | 干净安装;如果是登录用户,服务端数据仍保留 |
| SD卡安装(Android) | APK移到SD卡安装 | 安装和运行正常 |
| 外部存储迁移 | 应用设置中迁移到SD卡 | 迁移后功能正常 |
五、性能测试
5.1 响应时间基准
| 指标 | 合格 | 优秀 | 测试方法 |
|---|---|---|---|
| 冷启动 | < 3秒 | < 1.5秒 | 杀进程后手动计时 |
| 热启动 | < 1秒 | < 500ms | 按Home后再打开 |
| 页面切换 | < 500ms | < 200ms | 开发者选项 → GPU呈现模式 |
| 接口响应 | < 1秒 | < 300ms | Charles 查看请求耗时 |
| 图片加载 | < 2秒 | < 1秒 | 弱网下降级对比 |
| 滑动帧率 | > 55fps | > 58fps | 开发者选项 → 显示帧率 |
5.2 内存测试
测试工具:
| 平台 | 工具 |
|---|---|
| Android | Android Studio Profiler / PerfDog / adb shell dumpsys meminfo |
| iOS | Xcode Instruments / PerfDog |
关键内存指标:
| APP类型 | 空闲内存 | 正常使用 | 高风险值 |
|---|---|---|---|
| 工具类APP | < 80MB | < 200MB | > 300MB |
| 音视频APP | < 100MB | < 300MB | > 500MB |
| 游戏APP | < 200MB | < 800MB | > 1.2GB |
| 大型3D游戏 | < 500MB | < 1.5GB | > 2GB |
内存泄漏检测:
内存泄漏最直接的表现是:反复做同一操作,内存只升不降。
步骤:
- 启动APP → 记录初始内存
- 反复执行目标操作20次(如反复打开关闭详情页)
- 返回首页 → 手动触发GC → 再次记录内存
- 如果内存明显高于初始值(高出30%以上),大概率存在泄漏
常见泄漏原因:
| 原因 | 表现 |
|---|---|
| 静态变量持有Activity/Fragment引用 | 页面销毁后内存未释放 |
| 匿名内部类持有外部引用 | Handler/Runnable未在onDestroy移除 |
| 单例持有Context | 传入Activity的Context(应该用ApplicationContext) |
| 资源未关闭 | Cursor/InputStream/Bitmap 用完没关 |
5.3 CPU测试
测试工具:
| 平台 | 工具 |
|---|---|
| Android | Android Studio Profiler / PerfDog / top命令 |
| iOS | Xcode Instruments |
| APP状态 | CPU正常范围 |
|---|---|
| 前台空闲 | < 5% |
| 前台滚动列表 | < 20% |
| 前台播放音频 | < 10% |
| 前台复杂动画 | < 30%(瞬时峰值可到50%) |
| 后台 | < 5%(不应持续占用CPU) |
CPU异常场景:切到后台后CPU仍然高占用------可能在后台偷跑计算、动画未暂停、定时器未清除。
5.4 后端接口压力测试(JMeter)
后端性能和APP体验直接挂钩,用 JMeter 做后端压测:
第一:基准测试(单用户)
线程数=1,循环=10次
目的:获取单用户下每个接口的响应时间基线
第二:负载测试(模拟日常峰值)
线程数=50,Ramp-Up=10秒,持续5分钟
目的:模拟日常最高用户量的表现
第三:压力测试(找拐点)
| 轮次 | 并发数 | 持续时间 | 目的 |
|---|---|---|---|
| 1 | 100 | 5分钟 | 2倍负载 |
| 2 | 200 | 5分钟 | 4倍负载 |
| 3 | 500 | 5分钟 | 10倍负载,找拐点 |
第四:稳定性测试
线程数=200,持续30分钟
目的:验证长时间运行是否有内存泄漏、连接池满等问题
JMeter核心监听器解读:
| 指标 | 含义 | 参考标准 |
|---|---|---|
| Average(平均响应时间) | 所有请求的平均耗时 | < 1秒 |
| Median(中位数) | 50%请求的耗时 | < 800ms |
| 90% Line | 90%请求的耗时不超过此值 | < 1.5秒 |
| 95% Line | 95%请求的耗时不超过此值 | < 2秒 |
| Throughput(TPS) | 每秒处理的事务数 | 越高越好 |
| Error% | 错误率 | 必须 < 1% |
六、安全测试
6.1 数据存储安全
| 检测项 | 要求 | 测试方法 |
|---|---|---|
| 密码 | 不允许本地明文存储 | 检查 SharedPreferences/UserDefaults/keychain |
| Token | 存储在 Keychain(iOS)/Keystore(Android) | 检查存储位置是否为安全区域 |
| 数据库文件 | SQLite DB 文件是否可被外部读取 | root 手机进入 /data/data/包名/databases/ 查看 |
| 缓存文件 | 缓存中是否有敏感信息 | 检查 /cache 目录下的文件内容 |
| 日志文件 | 日志不打印Token/密码/手机号 | 查看 logcat 或控制台输出 |
Android 特别检查:
// 检查 SharedPreferences 是否存储敏感信息
adb shell
run-as com.example.app
cat shared_prefs/*.xml
// 检查 SQLite 数据库是否明文
cd databases
sqlite3 app.db
.tables
SELECT * FROM user;
6.2 数据传输安全
| 检测项 | 测试方法 | 处理 |
|---|---|---|
| HTTPS强制 | 修改代码中的https为http,验证是否能发送 | 应被系统或框架拦截 |
| 证书校验 | Charles代理抓包,安装Charles证书后验证APP是否仍然信任 | 应校验失败拒绝连接(SSL Pinning) |
| 密码/验证码明文 | 抓包查看登录接口的请求体 | 密码应加密(至少base64,最好hash+salt) |
| Token有效期 | 拿到Token后修改系统时间或等待过期 | 过期后401,有刷新机制 |
6.3 权限与越权
| 检测项 | 测试方法 |
|---|---|
| 横向越权 | 用户A登录,修改请求中的userId为B的ID,查看B的数据 |
| 横向越权-订单 | 修改订单ID为其他用户的订单号 |
| 纵向越权 | 普通用户token请求管理员接口 |
| 未授权访问 | 不携带Token请求需要登录的接口 |
| Token篡改 | 修改JWT Token中的payload部分(如把role从user改为admin)然后编码 |
| 支付金额篡改 | 抓包修改下单请求中的金额参数 |
6.4 反编译与代码安全
| 平台 | 反编译工具 | 防护建议 |
|---|---|---|
| Android APK | apktool/jadx/jeb | 核心逻辑放服务端;代码混淆(ProGuard/R8);字符串加密 |
| iOS IPA | class-dump/Hopper | Bitcode编译;代码混淆;关键字符串不要硬编码 |
七、UI自动化测试
7.1 Appium:跨平台UI自动化
Appium 是目前使用最广的移动端UI自动化框架,支持 iOS 和 Android。
架构原理:

python
from appium import webdriver
from appium.webdriver.common.appiumby import AppiumBy
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# 连接设备
desired_caps = {
"platformName": "Android",
"platformVersion": "14",
"deviceName": "Pixel 7",
"appPackage": "com.aitingwaiyu.app",
"appActivity": ".ui.login.LoginActivity",
"noReset": True # 不清除APP数据
}
driver = webdriver.Remote("http://localhost:4723/wd/hub", desired_caps)
# 等待元素并操作
wait = WebDriverWait(driver, 10)
phone_input = wait.until(
EC.presence_of_element_located((AppiumBy.ID, "com.aitingwaiyu.app:id/et_phone"))
)
phone_input.send_keys("13800138000")
login_btn = driver.find_element(AppiumBy.ID, "com.aitingwaiyu.app:id/btn_login")
login_btn.click()
# 断言
toast = wait.until(
EC.presence_of_element_located((AppiumBy.XPATH, "//android.widget.Toast"))
)
assert "请输入验证码" in toast.text
driver.quit()
7.2 元素定位方式
| 优先级 | 定位方式 | 示例 | 适用场景 |
|---|---|---|---|
| 1 | accessibility id | AppiumBy.ACCESSIBILITY_ID, "登录按钮" |
iOS/Android通用,最推荐 |
| 2 | resource-id | AppiumBy.ID, "com.xx:id/btn_login" |
Android专用 |
| 3 | xpath | AppiumBy.XPATH, "//android.widget.Button[@text='登录']" |
兜底方案,最慢 |
| 4 | class name | AppiumBy.CLASS_NAME, "android.widget.EditText" |
同类型元素多时不推荐 |
| 5 | UIAutomator | AppiumBy.ANDROID_UIAUTOMATOR, 'text("登录")' |
Android专用,比xpath快 |
7.3 Page Object 模式
python
class LoginPage:
"""登录页面"""
def __init__(self, driver):
self.driver = driver
self.phone_input = (AppiumBy.ID, "et_phone")
self.code_btn = (AppiumBy.ID, "btn_get_code")
self.login_btn = (AppiumBy.ID, "btn_login")
def login(self, phone, code):
self.driver.find_element(*self.phone_input).send_keys(phone)
self.driver.find_element(*self.code_btn).click()
# 输入验证码...
self.driver.find_element(*self.login_btn).click()
return HomePage(self.driver)
class HomePage:
"""首页"""
def __init__(self, driver):
self.driver = driver
def get_user_name(self):
return self.driver.find_element(AppiumBy.ID, "tv_user_name").text
# 用例
def test_login():
login_page = LoginPage(driver)
home_page = login_page.login("13800138000", "123456")
assert home_page.get_user_name() == "测试用户"
八、APP测试检查清单
功能测试
正向流程:核心场景端到端走通
异常流程:错误输入、异常操作
边界值:输入极限值、临界时间点
权限:首次授予/拒绝/二次触发/手改权限
手势:左滑删除/下拉刷新/长按菜单/双击/侧滑返回
兼容性测试
Android 10-15 系统版本
iOS 15-18 系统版本
华为/小米/OPPO/vivo/三星 各至少一台
1080p 基准分辨率 + 720p + 2K
折叠屏 + 平板 + 全面屏挖孔刘海
输入法:搜狗/百度/系统自带
专项测试
弱网:2G/3G/弱4G/弱WiFi/网络抖动/100%丢包
网络切换:WiFi↔4G↔飞行模式
中断:来电/短信/闹钟/低电量/后台/锁屏
耗电:后台静置/在线播放/GPS定位 各1小时
流量:首次启动/列表页/详情页/流媒体10分钟
安装/升级/卸载/重装
性能测试
冷启动 < 3秒
反复操作无内存泄漏
后台CPU < 5%
滑动帧率 > 55fps
后端接口90%Line < 1.5秒
安全测试
全站HTTPS + 证书校验(SSL Pinning)
Token存Keychain/Keystore
横向越权 + 纵向越权
密码/验证码加密传输
日志无敏感信息打印