

某自动化测试项目里,有一个脚本写了三年,从最初的几十行,长成了一个三百多行的单体函数——登录、建草稿、发布文章、检查首页展示、清理数据,全挤在一个函数里,中间还散布着六七个sleep(3),没人说得清哪个是真的必要,哪个是当年随手加上去"先让测试过了再说"的补丁。新人接手这个项目时,唯一敢做的事就是在文件末尾继续往后加代码,不敢动前面一行——这就是典型的"屎山脚本"。
测试代码长期被当成二等代码,缺review、缺重构纪律,只要还能跑通,就没人有动力回头整理。复制粘贴永远比抽一个公共方法更快,尤其是在deadline压力下,新增一个测试场景,最省事的做法就是复制一份已有的脚本改几行,而不是花时间重构出可复用的部分。sleep是最快的止血手段:遇到一次偶发失败,不去查原因,加个sleep让它先过,过了就不再回头看。等原作者离职,新人面对一堆叫不出名字的代码和莫名其妙的等待时间,没人敢删——谁也不知道哪一行是"有用的"。
第一类是拆分过长函数:把整个函数喂给AI,让它读懂逻辑边界,把登录、创建草稿、发布、校验、清理这几个天然独立的步骤,拆成命名清晰的小函数,原来那个三百行的怪物变成五六个几十行、各管一段的函数,每个函数名字本身就是一段说明文档,不用再从头读到尾才能搞懂某一段在干什么。第二类是提取公共步骤:跨多个测试文件扫描,找出几乎一字不差的登录、初始化代码块,统一抽成共享的辅助方法或Page Object,改一处就能让所有调用的地方同步生效,而不是要去十几个文件里逐个改——这跟之前讨论流量降噪时提到的语义聚类去重,其实是同一种思路换了个应用场景。第三类是优化等待逻辑:把硬编码的sleep换成针对具体条件的显式等待——等某个按钮变成可点击状态、等某个网络请求真正结束,而不是一刀切地"先等三秒再说"。
重构前的脚本是这样的:一个三百多行的单体测试函数,里面散布着六个sleep(3),而登录这一段代码,几乎一字不差地,在另外八个测试文件里各复制了一遍。把这个脚本和它的调用上下文丢给AI做重构分析,得到的方案是:拆出login()、create_draft()、publish_article()、verify_on_homepage()、cleanup()五个函数;把login()抽到共享的Page Object里,八个文件里重复的登录代码全部替换成调用这一个共享方法;六个sleep(3)里,五个被替换成针对具体元素状态的显式等待,比如等发布按钮真正可点击、等草稿保存成功的提示出现。
剩下那一个sleep(3),AI建议直接删掉,因为它前后看起来没有对应任何明显的UI状态变化。删掉之后跑了几轮,测试开始偶发失败——往下排查才发现,这个sleep原来在悄悄掩盖一个真实的问题:文章发布成功后,首页列表要等异步任务刷新缓存,大概一到两秒才会真正更新,原作者当年大概是发现了这个时间差,没有去推动后端加重试或者优化缓存刷新逻辑,而是简单粗暴地用sleep(3)把这个问题盖了过去。AI的这次"优化",反而把一个被掩盖了好几年的真实缺陷重新暴露了出来——这不是重构引入的新问题,是重构撕开了一直没被解决的旧问题。团队最后没有简单地把sleep(3)加回去,而是把"检查首页展示"这一步换成了带超时的轮询等待,同时把这个缓存刷新延迟的问题报给了后端,作为一个真正的缺陷跟进,而不是继续靠测试脚本里的等待时间来掩盖。
没有安全网就大改,是最容易出事的一种做法。重构前最好先把现有脚本多跑几十次,记录下哪些步骤本来就偶尔失败,作为重构后对比的基线,否则分不清新冒出来的问题是重构引入的,还是本来就藏在那里的。看到sleep不能直接当成理所当然该清掉的技术债,最好先去查一查它当年到底在等什么——上面那个案例已经说明了,有些sleep是真的在掩盖一个尚未解决的缺陷,删掉它意味着要面对那个一直被回避的问题,而不只是清理代码。提取公共步骤的时候也要小心,两段看起来很像的代码,未必真的承担同一个业务含义,如果不加判断地把它们合并成一个共享方法,后续两边各自演化出不同需求时,反而会让这个"公共方法"变得里面全是if-else分支,比重构前还难维护。另外,不建议一次性对几百个脚本做批量重构,从影响范围小、跑得频繁的脚本开始,观察一段时间确认稳定,再逐步推广到更多脚本会更稳妥。
重构前先建立一份基线:把现有脚本多轮跑几十次,记录通过率和耗时分布,作为后续对比的参照。让AI先输出重构方案而不是直接改代码,方案里清楚标注每一处sleep被换成了什么等待条件、哪些代码块被合并到了共享方法里,由人工审核确认后再执行,而不是看到一份"重构完成"的diff就直接合并。把删除或替换某个sleep的原因写进commit信息或代码注释里,方便后面的人理解这处改动背后发生过什么,而不是留下又一段无人敢碰的代码。重构完成后,按小范围验证、观察一段时间、再推广这个节奏推进,而不是图省事一次性铺开到所有脚本。
屎山脚本不是一天写出来的,是几年没人敢动慢慢攒出来的。AI能帮上忙的,是把拆分函数、去重代码、优化等待这几件机械但费时的事做得更快——但真正决定这次重构靠不靠谱的,还是有没有先建好安全网,敢不敢去查清楚每一行看似多余的代码,当年到底在防着什么。