K8s CronJob 配置,每天凌晨2点执行移动端回归测试
聊聊我在杭州创业公司搞移动端自动化测试的血泪史
上周五晚上十一点半,我盯着MacBook Pro屏幕上Appium抛出的那一长串红彤彤的报错日志,猛灌了一口已经凉透的冰美式,真的有种想把键盘砸了的冲动。
先交代下背景吧,坐标杭州,在一家刚拿到A轮的创业公司当全栈。说是全栈,其实就是啥都干,前端Vue、后端Go、运维部署,甚至有时候还得客串一下产品。我个人习惯用Mac开发,毕竟Unix环境写代码舒服,但Windows也不能少,主要用来跑Android Studio测App,顺便应对一些只有IE或者老旧Windows环境才有的奇葩兼容问题。因为平时自己瞎折腾比较多,对云原生和K8s还算熟悉,所以公司里的CI/CD和容器化基本都被我包揽了。
最近公司业务发展快,移动端App迭代速度从一个月一版变成了两周甚至一周一版。这就导致了一个致命问题:每次发版前的回归测试简直是噩梦。我们这种小团队,根本没有专职的测试团队,全靠开发互相交叉自测,或者让产品经理硬着头皮上。
上周四,产品经理在iOS提审前随便点了两下,觉得没问题就提交了。结果第二天苹果审核直接给拒了,理由是一个在iPhone SE(第三代)上的UI重叠问题。当时产品经理那个眼神,感觉下一秒就要让我背锅。安卓那边更别提了,华为、小米、OV各大应用市场的审核玄学,经常因为一些莫名其妙的权限问题或者隐私合规被打回。每次重新打包、上传、等审核,半天时间就没了,严重拖延了项目deadline。
痛定思痛,我决定搞一套移动应用自动化测试流程。其实以前也搞过,但维护成本太高,UI稍微改个按钮位置,一堆脚本就全挂了,最后大家还是回到了手工点点点的老路。
这次破局的契机,是我上个月看了一本讲AI工程化落地的书籍。书里提到了用大模型来辅助生成和维护测试代码的思路,让我茅塞顿开。既然手工写脚本太累,那让AI来写不就行了?
说干就干。我先把主力开发工具VS Code里的AI插件换成了 Cline。这玩意儿确实猛,不同于那种只能补全代码的插件,Cline能直接读取整个项目的上下文,甚至能执行终端命令。我让它读取App的UI树结构(通过Appium Inspector导出的XML),然后直接下达指令:“根据这个UI结构,用Python和Appium写一个登录和首页浏览的自动化测试脚本,要求包含显式等待和异常捕获。”
你别说,Cline生成的代码质量还真不错,连Page Object设计模式都给我用上了。不过AI嘛,偶尔也会犯幻觉,比如它有时候会编造一些不存在的元素ID,这时候就得靠我这个“老全栈”来人工兜底了。
解决了脚本编写的问题,接下来是测试用例的生成。每次让产品经理写用例,那格式简直惨不忍睹。我灵机一动,用 FastGPT 搭建了一个内部的测试知识库。我把历史的需求文档(PRD)、过去的Bug单、还有UI设计规范全都转成PDF喂给FastGPT。
配置好RAG(检索增强生成)后,效果出奇的好。现在每次有新需求,我只需要在FastGPT里输入:“根据最新的支付模块PRD,生成包含正常流程和至少3种异常中断流程的测试用例”。几秒钟后,一份结构清晰、覆盖全面的测试用例就出来了。然后我把这份用例直接丢给Cline,让它转化成具体的自动化断言代码。这套“FastGPT生成用例 + Cline编写代码”的组合拳,直接把测试准备时间缩短了70%。
既然脚本有了,怎么跑也是个问题。总不能每次都在我自己的Mac上跑吧,太占资源了。这时候我的K8s老本行就派上用场了。我写了一个K8s CronJob,每天凌晨两点自动拉取最新的测试镜像,启动Appium Server和模拟器集群执行回归测试。
这里分享一段核心的K8s Job配置和Cline帮我优化的Appium脚本片段:
apiVersion: batch/v1
kind: CronJob
metadata:
name: mobile-app-regression
spec:
schedule: "0 2 * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: appium-tester
image: registry.cn-hangzhou.aliyuncs.com/mycompany/appium-test:latest
resources:
requests:
memory: "2Gi"
cpu: "1"
limits:
memory: "4Gi" # 限制内存,防止模拟器把节点撑爆
env:
- name: APP_PACKAGE
value: "com.mycompany.app"
restartPolicy: OnFailure
# Cline 生成的 Appium 核心测试代码片段
from appium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
def test_login_flow(driver):
# 使用显式等待,比死等靠谱多了
wait = WebDriverWait(driver, 15)
# 输入账号
username_input = wait.until(
EC.presence_of_element_located((By.ID, "com.mycompany.app:id/et_username"))
)
username_input.clear()
username_input.send_keys("test_user")
# 点击登录,这里Cline特意加了try-catch处理弹窗
try:
login_btn = driver.find_element(By.ID, "com.mycompany.app:id/btn_login")
login_btn.click()
except Exception as e:
print(f"登录按钮点击失败,可能有隐私协议弹窗: {e}")
handle_privacy_popup(driver)
# 断言首页元素是否加载
wait.until(EC.presence_of_element_located((By.ID, "com.mycompany.app:id/tv_home_title")))
assert driver.find_element(By.ID, "com.mycompany.app:id/tv_home_title").text == "首页"
在移动应用测试这块,除了功能自动化,我还特别关注平台适配和性能。安卓碎片化太严重了,我利用云真机平台结合自动化脚本,跑了Top 20的主流机型。顺便提一句,在测试过程中发现了一个严重的内存泄漏问题,是在快速滑动列表时触发的。用性能工具一抓,发现是图片缓存没做回收。赶紧让前端兄弟修了,不然上线后肯定被用户骂卡顿。
至于应用市场发布,我现在把自动化测试集成到了发布流水线里。只有当自动化测试通过率100%,且Monkey测试运行30分钟无Crash时,才会触发打包脚本,生成Release包并自动上传到 fir.im 和 蒲公英,最后通过钉钉机器人把测试报告和下载链接发给产品经理。
搞了这一个多月,最大的心得就是:自动化测试不是为了完全替代人工,而是为了给开发和产品兜底,把那些重复、枯燥的点点点交给机器,让人去关注更复杂的业务逻辑和用户体验。
虽然过程很折腾,中间也踩了不少环境配置和脚本维护的坑,但看着现在每次发版前那绿色的测试通过报告,心里还是挺有成就感的。顺便说一句,最近把这套自动化实践整理了一下写进简历,周末去阿里和网易面了两轮,感觉还不错,希望能有个好结果吧,毕竟创业公司的全栈,真的太需要涨点工资来抚慰我受伤的腱鞘炎了。


评论 0