移动应用测试自动化实践:从“人肉点”到“自动跑”的那些事儿

一键启动人生
2025-06-13 03:32
阅读 241

开篇:从零开始,为什么我们非得搞自动化?

开篇:从零开始,为什么我们非得搞自动化?

我至今还记得那年冬天,团队开发了一款面向企业用户的跨平台移动应用。当时项目刚进入上线前的冲刺阶段,每次发版都伴随着大量的手动回归测试工作,每天早上第一件事就是打开手机,一个界面一个界面地点按钮、看日志、录视频……整个人就像被绑在了“点点点”的机器上。

有一次版本迭代比较频繁,一天提测两次,那天晚上我加班到凌晨三点才搞定当天的测试任务,第二天早上发现又有一个紧急Hotfix需要验证。那种身心俱疲的感觉让我意识到一个问题:如果继续靠人肉来做测试,这条路是走不通的。

于是我们开始推动测试自动化的落地。但说实话,过程远没有想象中顺利。


问题描述:测试自动化不是加个脚本就完事

移动设备适配-1

问题描述:测试自动化不是加个脚本就完事

一开始我们都天真地认为:“不就是写个脚本来模拟点击吗?找几个开源框架一搭,应该很简单。”

但现实狠狠打了我们一巴掌。

我们的应用同时支持 Android 和 iOS,UI 层使用的是 React Native,底层通信依赖原生模块,接口还涉及到一些旧系统改造后的遗留接口。这就导致我们在做自动化的时候,遇到了几个非常棘手的问题:

  1. 跨平台适配差:Android 和 iOS 的元素定位方式不同,代码无法复用。
  2. 控件识别不稳定:React Native 渲染出来的 View 没有明确的 resource-id,Appium 定位困难。
  3. 网络环境复杂:有些接口请求失败或者慢加载,导致自动化脚本经常失败。
  4. CI 集成成本高:本地运行没问题,一上 CI 就各种出错,甚至找不到设备。
  5. 缺乏统一规范:前端没给控件打 tag,写脚本全靠猜 ID,维护起来极其痛苦。

最离谱的一次,我们写了个 UI 测试脚本跑了三天,结果因为某个页面换了个图标,整个流程就卡死了……


解决方案:选型+规范+平台化三管齐下

解决方案:选型+规范+平台化三管齐下

为了解决这些问题,我们并没有急于上代码,而是先做了几件关键的事。

第一步:技术选型稳扎稳打

经过多次讨论和技术调研,我们决定采用以下组合:

  • 框架层:Appium + WebdriverIO(支持多语言,社区活跃)
  • 测试语言:JavaScript/TypeScript(与前端技术栈统一,降低学习成本)
  • 持续集成工具:GitHub Actions + Docker
  • 云测平台辅助:初期使用 AWS Device Farm 做兼容性测试
  • 日志和报告:Allure + Mochawesome Report

第二步:建立控件命名规范

这是我们吃过最大的亏之一。后来我们和前端达成共识:

  • 所有可交互控件必须加上 testID,格式统一为 <pageName>_<element>,例如 login_button_submit
  • 页面切换时触发埋点日志,方便调试时判断是否成功跳转
  • 给每个页面加全局唯一的标识字段,作为测试脚本识别当前页面状态的依据

这个规范在后续脚本编写过程中起到了至关重要的作用。

第三步:构建公共函数库和封装方法

为了减少重复劳动和提高维护效率,我们封装了一系列常用的工具函数,比如:

  • 等待控件出现并点击
  • 获取 Toast 提示内容
  • 处理系统权限弹窗
  • 判断当前网络状态

举个例子:

// utils/waitUtil.js
async function waitForElementAndClick(selector, timeout = 10000) {
    try {
        const el = await $(selector);
        await el.waitForDisplayed(timeout);
        await el.click();
    } catch (error) {
        throw new Error(`Failed to wait and click element: ${selector}`);
    }
}

module.exports = { waitForElementAndClick };

通过这种方式,我们的核心业务流程测试脚本逐渐变得清晰、简洁,也更容易被其他成员接手维护。


踩坑经验:你以为的稳定其实很脆弱

踩坑经验:你以为的稳定其实很脆弱

在实际操作过程中,有很多“细节中的魔鬼”,踩过的坑现在回忆起来都觉得头皮发麻。

控件找不到,怎么办?

React Native 的组件往往没有 id,只能依赖文本或类名来找,这会导致识别率低下。我们最终采取了两个策略:

  1. 强制要求前端加上 testID,作为唯一定位标准。
  2. 对于动态生成的内容(如列表),采用 XPath 表达式结合部分匹配查找。

比如这段动态生成的用户列表:

// 使用 XPath 查找昵称为 "Tom" 的用户
const userCell = await $('//android.widget.TextView[contains(@text, "Tom")]/parent::*/parent::*');
await userCell.click();

虽然不太优雅,但在没有唯一id的情况下,这是可行的折中方案。

Appium连接断开,设备突然掉线?

这个问题在早期特别频繁。后来我们总结了几点经验:

  • 不要过度依赖 USB 设备连接,优先使用无线调试配合 CI。
  • 在 GitHub Actions 中,我们搭建了一个基于 Docker 的 Appium Server 环境,并使用安卓模拟器。
  • 对于某些奇怪的崩溃问题,可以考虑加一层重试逻辑:
async function retry(fn, retries = 3, delay = 3000) {
    for (let i = 0; i < retries; i++) {
        try {
            return await fn();
        } catch (e) {
            if (i === retries - 1) throw e;
            console.log(`Retry ${i + 1}:`, e.message);
            await browser.pause(delay);
        }
    }
}

效果总结:效率提升看得见

实施自动化之后,我们明显感觉到了几个方面的改善:

指标 优化前 优化后
回归测试耗时 2小时以上 20分钟以内
版本发布准备时间 至少半天 数分钟即可启动测试
bug漏测率 约15% 下降至3%以内
成员参与度 只有测试同学做 前端、QA、DevOps 共同维护

除了这些数据指标上的提升,更重要的是建立了良好的协作氛围。大家开始重视“可测试性设计”,从前端到后端都有了“要让别人好测试”的意识。


经验分享:几点建议送给正在路上的你

1. 不要急着写第一个测试用例

先定规范,再搭框架,否则后期维护会非常麻烦。

2. 把自动化当成产品来看待

自动化不是一次性的任务,它需要持续维护和改进。要有监控、有报警、有问题追踪机制。

3. 优先覆盖核心路径

刚开始不必追求全覆盖,先抓住最关键的路径。比如登录、下单、支付这些流程,优先保证稳定性。

4. 性能和体验也是测试的一部分

别忘了,测试不仅仅是为了功能正确,还包括性能表现和用户体验。我们可以加入一些性能埋点,比如页面渲染时间、接口响应速度等,做基本的监控。

比如:

it('should load home page within 2 seconds', async () => {
    const startTime = Date.now();
    await HomePage.open();
    const duration = Date.now() - startTime;
    expect(duration).toBeLessThanOrEqual(2000); // 2s 内完成加载
});

移动应用界面设计-2

5. 上架前务必实机测试

不管自动化多完善,在上传到各大应用市场之前,还是一定要进行真机验证。尤其是 iOS,苹果对自动登录、截图录制等敏感行为审查非常严格,很容易被打回。


结语:测试自动化是一场马拉松

回头来看,从最初的“人肉点点点”到如今自动化流水线能自己跑完整个测试流程,真的不容易。

但值得庆幸的是,这一路我们没有放弃,也没有盲目跟风,而是结合自身产品的实际情况,踏踏实实地走出了一条适合自己的自动化之路。

希望这篇分享能帮你在移动应用测试自动化的路上少走些弯路。如果你也在做相关的事情,欢迎留言交流,一起成长!


评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝