移动应用测试自动化实践:一个斜杠程序员的血泪经验
大家好,我是老K,白天在某中型互联网公司当“人肉API接口”,晚上接外包搞副业,顺便研究点云原生和K8s(虽然家里那台Mac Mini跑Minikube经常卡成PPT)。最近半年主要在折腾一个跨平台移动项目,前端用的是React Native,后端是Go+Node混搭——别问,问就是历史包袱。
上周五晚上11点,我正一边撸着猫一边在VSCode里狂敲代码(插件装了37个,启动慢得像老年机),产品经理突然在钉钉上@我:“老K,下周三上线,测试那边说回归测不过来,能不能搞个自动化?”
我内心OS:你早干嘛去了?双11压测的时候你不提,现在临上线三天说这个?
但没办法,谁让我是个靠口碑接外包的斜杠青年呢?今天这篇文章,就聊聊我在移动应用测试自动化这条路上踩过的坑、熬过的夜,以及最终怎么把这套流程跑起来的。
为啥非得搞自动化?因为手动测试真的会疯
我们这个项目是个电商类App,支持iOS和Android双端。每次迭代都有几十个页面改动,光登录、购物车、支付这三个核心路径,手动跑一遍就得半小时。测试同学小王已经连续加班两周,头发都快比我这个35岁老码农还少了。
更惨的是,上个月有一次上线,因为Android 12的权限弹窗样式变了,前端没适配,结果支付按钮被遮住,用户根本点不到!线上投诉炸锅,运维半夜把我电话打爆,我当时真的想砸电脑。
所以,自动化测试不是可选项,而是保命符——尤其当你面对多个机型、多个OS版本、还要兼顾用户体验和性能的时候。
技术选型:别整花活,稳定压倒一切
一开始我想直接上Appium,毕竟社区大、文档多。但试了两天发现,在真实项目里跑起来太脆了:
- 元素定位经常失效(特别是React Native生成的View层级嵌套深得离谱)
- Android模拟器启动慢得像树懒
- iOS真机调试还得配证书,烦死了
后来一咬牙,改用 Detox + Jest 组合(专为React Native优化),配合 Firebase Test Lab 做真机云测。虽然学习曲线陡了点,但稳定性提升了一个数量级。
💡 小贴士:如果你不是RN项目,纯原生的话,iOS可以用XCTest + Fastlane,Android用Espresso + Gradle,但跨平台还是推荐Detox或Maestro(后者最近很火,但生态还不成熟)。
实战:从零搭建自动化流水线
第一步:本地跑通一个测试用例
先装依赖(我用的是Yarn):
yarn add detox jest --dev
npx detox init -r jest
然后配置 detox.config.js:
// detox.config.js
module.exports = {
testRunner: 'jest',
runnerConfig: 'e2e/jest.config.js',
apps: {
'ios.debug': {
type: 'ios.app',
binaryPath: 'ios/build/Build/Products/Debug-iphonesimulator/MyApp.app',
build: 'xcodebuild -workspace ios/MyApp.xcworkspace -scheme MyApp -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build'
},
'android.debug': {
type: 'android.apk',
binaryPath: 'android/app/build/outputs/apk/debug/app-debug.apk',
build: 'cd android && ./gradlew assembleDebug assembleAndroidTest -DtestBuildType=debug'
}
},
devices: {
simulator: {
type: 'ios.simulator',
device: { type: 'iPhone 14' }
},
emulator: {
type: 'android.emulator',
device: { avdName: 'Pixel_5_API_33' }
}
},
configurations: {
'ios.sim': {
device: 'simulator',
app: 'ios.debug'
},
'android.emu': {
device: 'emulator',
app: 'android.debug'
}
}
};
写个最简单的登录测试(e2e/login.test.js):
describe('Login flow', () => {
beforeEach(async () => {
await device.reloadReactNative(); // 热重载,省得重启App
});
it('should login successfully', async () => {
// 等待首页加载完成
await waitFor(element(by.id('welcome-screen')))
.toBeVisible()
.withTimeout(5000);
// 点击“登录”按钮
await element(by.id('login-button')).tap();
// 输入账号密码
await element(by.id('email-input')).typeText('test@example.com');
await element(by.id('password-input')).typeText('123456');
// 提交
await element(by.id('submit-login')).tap();
// 验证是否跳转到主页
await waitFor(element(by.id('home-screen')))
.toBeVisible()
.withTimeout(10000);
});
});
注意几个坑:
by.id()必须在前端代码里显式加testID属性(React Native里是testID="xxx"),否则找不到元素。- Android上
typeText有时会失败,建议加clearText()先清空。 - 真机测试时,iOS的Keychain可能缓存登录态,记得在
beforeEach里清理。
第二步:搞定跨平台兼容性
不同平台的UI差异是最大痛点。比如:
| 平台 | 导航栏高度 | 弹窗动画 | 字体渲染 |
|---|---|---|---|
| iOS | 44pt | 滑入 | San Francisco |
| Android | 56dp | 淡入 | Roboto |
我们在前端组件库里统一加了 platform-specific 标记,并在测试中做条件判断:
const isIOS = device.getPlatform() === 'ios';
it('handles platform differences', async () => {
if (isIOS) {
await expect(element(by.id('ios-only-banner'))).toBeVisible();
} else {
await expect(element(by.id('android-fab-button'))).toBeVisible();
}
});
另外,性能监控也得跟上。我们在每个关键路径后加了FPS和内存检查:
afterEach(async () => {
const perf = await device.getPerformanceStats();
console.log(`FPS: ${perf.fps}, Memory: ${perf.memory}`);
expect(perf.fps).toBeGreaterThan(50); // 低于50帧就报警
});
第三步:集成到CI/CD,让自动化真正“自动”
我在家搭了个GitLab Runner(其实是Mac Mini兼职),配合Fastlane实现一键触发:
# Fastfile
lane :run_detox do
sh("detox test -c ios.sim --headless")
sh("detox test -c android.emu --headless")
end
但本地模拟器终究不够真实。于是我把关键用例扔到Firebase Test Lab跑真机:
gcloud firebase test android run \
--type instrumentation \
--app android/app/build/outputs/apk/debug/app-debug.apk \
--test android/app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk \
--device model=redfin,version=33,locale=en,orientation=portrait \
--device model=iPhone14,version=16.0,locale=en
每周日凌晨2点自动跑全量回归,结果发到企业微信群。测试同学终于能睡个整觉了(虽然产品经理又开始提新需求了……)。
效果如何?数据说话
上线这套自动化后,我们:
- 回归测试时间从 3小时 → 25分钟
- 线上P0级Bug下降 70%
- 发布节奏从 月更 → 双周更
最重要的是,我不用再半夜被叫起来修“按钮点不了”的问题了!
当然,也不是没有代价:
- 初期投入约 2周 搭建和调试
- 需要前端配合加
testID(为此我还请前端小哥喝了三杯瑞幸) - 维护成本依然存在(每次大改UI都要同步更新测试脚本)
给同行的几点建议
- 别追求100%覆盖:核心路径(登录、支付、下单)必须覆盖,边缘功能可以手动。
- 前端和测试要坐一起:最好让前端自己写部分E2E测试,理解成本最低。
- 真机测试不能省:模拟器跑得再稳,也抵不过小米OV的真实碎片化生态。
- 监控比测试更重要:结合Sentry、Firebase Crashlytics做线上行为追踪,自动化只是第一道防线。
最后说句实在话:搞自动化不是为了炫技,而是为了让自己早点下班。毕竟,我还有两个外包项目等着交付,K8s集群也还没调优完呢!
如果你也在搞移动测试自动化,欢迎评论区交流(或者私信接外包,价格好说 😎)。
本文所有代码已在GitHub脱敏开源,搜索 “k-dev/mobile-test-demo” 即可。
P.S. 别忘了给你的VSCode装上 Detox Snippets 插件,少写80%样板代码!

评论 0