移动应用测试自动化?我摸鱼时顺手搞定了
上周五晚上,我正刷着 B 站“躺平哲学”视频,突然钉钉弹出一条消息:“小张,下周一上线前,测试覆盖率必须提到 80%。”——产品经理的语气像极了催命符。
我叹了口气,关掉 VSCode 里刚写了一半的 Spring Boot 微服务 demo(别问,问就是分布式系统兴趣使然),默默打开了公司那套祖传的移动端项目。
入职新公司才两个月,团队氛围倒是挺佛系,但上线节奏一点不含糊。我们做的是一个面向 C 端用户的 App,前端用 React Native 写的,后端是 Spring Boot + 区块链存证模块(对,你没看错,为了“可信”,硬塞了个轻量级联盟链)。问题是:每次改个按钮颜色,测试同学都要手动跑十几台真机+模拟器,效率低到让人想原地退休。
于是我想:与其等别人救我,不如自己动手,丰衣足食。反正摸鱼也是摸,不如摸点有用的——搞一套移动应用测试自动化流程。
自动化?听起来很卷,其实也没那么可怕
很多人一听“测试自动化”,脑海里立刻浮现 CI/CD、Selenium Grid、Appium 集群……但对我们这种中小团队来说,能跑通就行,先别追求完美。我的目标很简单:
让 UI 测试脚本在本地一键运行,不依赖测试同学手动点点点。
我翻了翻公司代码仓库,发现前端同事已经用 Jest + React Testing Library 写了一些单元测试,但端到端(E2E)测试几乎是空白。更离谱的是,区块链那部分接口居然只靠 Postman 手动验证——这要是线上出问题,怕不是要背锅到明年。
于是我决定从三方面入手:
- 前端 UI 自动化:用 Appium + WebDriverIO 覆盖核心路径(比如登录、提交表单)
- 后端接口验证:用 Spring Boot Test 写集成测试,顺便 mock 区块链节点
- 跨端兼容性:确保 iOS 和 Android 表现一致(别问我为什么,上次因为安卓字体渲染偏移 2px 被用户骂上应用商店)
Appium 搞起来,但别被坑死
说实话,第一次配 Appium 的时候,我差点卸载 VSCode。adb devices not found、Xcode signing failed、iOS simulator stuck on boot……这些问题轮番上阵,堪比打 Boss。好在我装了一堆插件(感谢 Remote - WSL、Appium Desktop、ESLint + Prettier 组合拳),总算把环境搭起来了。
关键配置其实就几行 wdio.conf.js:
// wdio.conf.js
exports.config = {
runner: 'local',
specs: ['./test/specs/**/*.js'],
capabilities: [{
platformName: 'Android',
'appium:deviceName': 'Pixel_4_API_30',
'appium:platformVersion': '11.0',
'appium:automationName': 'UiAutomator2',
'appium:app': path.join(process.cwd(), 'android/app/build/outputs/apk/debug/app-debug.apk')
}, {
platformName: 'iOS',
'appium:deviceName': 'iPhone 14',
'appium:platformVersion': '16.2',
'appium:automationName': 'XCUITest',
'appium:app': path.join(process.cwd(), 'ios/build/Build/Products/Debug-iphonesimulator/MyApp.app')
}],
// ...其他配置
};
注意:Android 路径和 iOS 路径完全不同,而且 iOS 必须用 .app 文件(不是 .ipa!),还得提前用 Xcode 编译过。我踩过的坑:直接拿 release 包跑,结果签名不匹配,Simulator 直接闪退。
测试脚本写起来倒挺爽,比如登录流程:
// test/specs/login.spec.js
describe('Login flow', () => {
it('should login successfully with valid credentials', async () => {
await $('~emailInput').setValue('user@test.com');
await $('~passwordInput').setValue('123456');
await $('~loginButton').click();
// 等待首页加载(带超时)
await expect($('~homeScreenTitle')).toBeDisplayed({ timeout: 10000 });
// 断言:检查是否跳转成功
const title = await $('~homeScreenTitle').getText();
expect(title).toEqual('Welcome!');
});
});
这里用了 ~ 前缀,代表 accessibility ID —— 这是跨平台最稳的方式,比 XPath 或 class name 可靠多了。前端同学只要在 RN 组件里加个 testID="loginButton" 就行,几乎零成本。
后端别拖后腿:Spring Boot + 区块链怎么测?
我们的 Spring Boot 服务有个 /api/submit 接口,会把用户提交的数据哈希后写入 Hyperledger Fabric 联盟链。但链节点不能随便 mock 啊?总不能每次测试都连真实网络吧?
灵机一动:用 @MockBean 把区块链客户端干掉!
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@TestPropertySource(properties = {
"blockchain.enabled=false" // 关键!测试时禁用真实调用
})
class SubmissionControllerTest {
@Autowired
TestRestTemplate restTemplate;
@MockBean
private BlockchainService blockchainService; // 模拟区块链服务
@Test
void shouldReturnSuccessWhenDataSubmitted() {
// 模拟区块链返回成功
when(blockchainService.write(anyString())).thenReturn("tx-12345");
ResponseEntity<String> response = restTemplate.postForEntity(
"/api/submit",
new SubmissionRequest("Hello World"),
String.class
);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(response.getBody()).contains("tx-12345");
}
}
这样,测试既快又安全,还不污染真实链数据。上线前再开 blockchain.enabled=true 跑一遍冒烟测试就行。
真机 vs 模拟器:别信“看起来一样”
有次我本地跑 Appium 测试全绿,结果 QA 说“安卓真机上按钮点不动”。查了半天才发现:某些低端机屏幕 DPI 不同,元素坐标偏移,导致点击失效。
解决方案?两点:
- 优先用 accessibility ID 定位(再次强调!)
- 加个 retry 机制:
const clickWithRetry = async (element, maxRetries = 3) => {
for (let i = 0; i < maxRetries; i++) {
try {
await element.click();
return;
} catch (e) {
console.warn(`Click failed, retry ${i + 1}/${maxRetries}`);
await browser.pause(1000);
}
}
throw new Error('Element click failed after retries');
};
另外,iOS 和 Android 的交互逻辑天然不同。比如 iOS 的 alert 弹窗要用 acceptAlert(),而 Android 可能是普通按钮。写测试时得分开处理,别幻想“一套脚本通吃”。
成果如何?摸鱼也有生产力
折腾两周后,我把 E2E 测试集成进了 GitLab CI:
# .gitlab-ci.yml
e2e_test:
stage: test
script:
- npm run build:android
- npm run build:ios
- npm run test:e2e
only:
- merge_requests
现在每次提 MR,流水线自动跑核心路径测试。上线前再也不用手动求测试同学加班了,他们甚至给我点了杯奶茶表示感谢(虽然可能是客套)。
最关键的是——我的摸鱼时间反而变多了。因为自动化挡住了 70% 的回归 Bug,剩下的问题基本是业务逻辑漏洞,而不是“点不到按钮”这种低级错误。
说点实在的:自动化不是银弹
别被网上那些“全自动无人值守”的宣传骗了。现实是:
| 项目 | 真实情况 |
|---|---|
| 维护成本 | 脚本经常因 UI 改动而失效,需持续更新 |
| 覆盖率 | 核心路径可覆盖,边缘场景仍需人工 |
| 速度 | 一次完整 E2E 测试约 8 分钟,不适合 TDD |
| ROI | 对频繁迭代的 App 极高,对静态页面意义不大 |
所以我的建议是:先自动化最关键的 3 条路径(比如注册、下单、支付),跑通后再扩展。别一上来就想覆盖 100% 场景,那只会把自己累死。
最后:技术人,既要躺平,也要有底线
写这篇文章时,我刚修完一个因时区问题导致的日期显示 Bug(UTC vs 本地时间,经典陷阱)。虽然日常佛系,但该搞定的事情,还是要搞定。
毕竟,摸鱼摸的是心态,不是责任。
用自动化把重复劳动干掉,剩下的时间,才能真正去研究分布式系统、区块链底层,或者——继续刷 B 站。
对了,如果你也在搞移动测试自动化,欢迎交流。
不过别在周五晚上找我,那时候我在躺平。

评论 0