自动化测试的九个常见错误:从设计到运维的避坑指南

发布时间:2026/10/12 0:20:24
自动化测试的九个常见错误:从设计到运维的避坑指南 做自动化测试这些年我带过十几个项目团队也接手过不少别人做不下去的自动化框架。见得最多的一个现象是项目刚启动时信心满满三个月后团队开始默默改脚本半年后这套“自动化”基本只剩下 CI 里那几个没人敢动的红点。这不是工具的问题也不是人的能力问题而是大多数人都踩在了同样的几个坑里。我常说自动化测试是一场高速公路驾驶起步谁都会但真正能保持高速、长时间不翻车的靠的不是一脚油门踩到底而是知道哪里有弯道、哪里有积水、哪里必须提前减速。这篇就把我这些年亲眼见过、亲身踩过、又亲手填平的九个最常见的自动化测试错误一个一个掰开揉碎讲清楚。每个错误都会说“为什么错”“会带来什么后果”“正确的姿势是什么”最后还会给一套可以直接照做的自查清单。不管你是刚准备引入自动化的测试负责人还是已经在维护一套半死不活脚本的倒霉蛋这篇文章应该都能帮你省下至少两个月的时间。1. 九个错误的整体视图先看清全局再动手1.1 自动化测试为什么总在“写脚本”阶段翻车先聊一个很有意思的现象绝大多数自动化测试项目不是死在技术难题上而是死在常识问题上。我甚至见过有的团队连被测系统的业务逻辑都没理清就急着开始写 UI 自动化脚本。等脚本写到一半开发把页面结构调整了一下几百个用例全部红掉然后项目就这么黄了。所以在我眼里自动化测试最核心的问题从来不是“用什么框架”“写什么代码”而是“你到底为什么自动化”“自动化哪些东西”“怎么让自动化跑得稳定”。这三个问题想不清楚后面无论怎么写都是给别人填坑。我梳理了一下最常见的错误可以分成三个层面设计层面金字塔结构建错、用例筛选拍脑袋、只测快乐路径。代码层面选择和页面结构强绑定、同步策略混乱、用例相互依赖。运维层面测试数据一塌糊涂、不稳定测试污染 CI、报告和失败信息完全不可用。这三个层面不是孤立的它们会在项目运行中互相放大。比如测试数据管理不好会把用例变不稳定用例不稳定会让 CI 大面积报红CI 报红多了团队就会开始跳过测试最后整个自动化体系失去信任没人再关注它。1.2 九个错误不是堆在一起而是一条完整的因果链这几个错误表面上看起来是“九条并列的问题”实际它们是一条因果链。设计期没想清楚代码期就会埋雷代码期埋了雷运行维护期就天天爆等到了维护期你已经不是在做自动化而是在做“自动化保洁”。我习惯把这条链画成这样的逻辑设计期错 → 写出的用例本身就带病比如大量低价值 UI 用例。实现期错 → 带病的用例变成不稳定用例比如选择器脆弱、同步混乱。运维期错 → 不稳定用例进入 CI团队每天被失败淹没自动化废弃。所以纠正也要从源头开始。很多团队只知道天天修“不稳定的选择器”却从没想过“这个用例本身是不是就不该出现在这套自动化里”。这就是为什么我特别坚持自动化测试里的稳定性和维护成本至少有 50% 是由早期设计决策决定的后面再怎么优化也只是在减轻症状而不是治疗病根。2. 设计期的三个坑决定你的自动化能不能活过三个月2.1 错误一UI 自动化头重脚轻整座金字塔是倒着盖的我每次接手存量自动化项目第一件事就是看他们的用例分布。最触目惊心的场景是一套自动化里 70% 以上都是 UI 层用例单元测试几乎没有API 层接口测试也寥寥无几。这个比例为什么是灾难我给你打一个比方。假设你要测一栋楼的水管系统最稳妥的办法是分三层来测水管阀门本身单元测试、楼层之间的主管道接口测试、最后是你家水龙头打开有没有水UI 测试。如果一上来就只盯着每个房间的水龙头做测试一旦楼上某节管道出了问题所有水龙头都会一起不出水但你根本分辨不出来问题到底出在哪一层。UI 自动化是所有自动化里最贵、最慢、最脆弱的一层。它依赖页面元素、依赖网络延迟、依赖浏览器版本、甚至依赖前端框架的渲染时机。一个页面样式调整可能导致几十个用例同时失败而失败原因只是某个按钮的位置变了功能一点问题都没有。合理的金字塔应该是底层单元测试占大头接口测试做骨架UI 测试只覆盖核心冒烟路径和关键用户旅程。我给大家一个可以直接抄的参考比例单元测试约 70%接口测试约 20%UI 层端到端测试约 10%注意这只是参考不是教条。有些业务系统因为历史原因没办法补单元测试那接口测试的比例可以适当上调。但无论如何不要让 UI 自动化成为你唯一的自动化防线。值得记住的一句话UI 测试的数量应该少到“即使它全部失败你也能在 10 分钟之内手工回归一遍”。如果做不到说明你的自动化金字塔已经建歪了。2.2 错误二只测快乐路径好像系统永远不会犯错第二个设计期的大坑是测试用例全部写在整个系统最正常的路径上。用户输入正确信息、服务器正常返回、数据库正常连接、第三方接口稳定响应。整条链路看起来完美无缺跑起来绿油油一片但你的自动化根本没有测出系统真实存在的大部分风险。我接过一个支付模块的自动化项目原有用例 120 多条覆盖率报告上看漂亮得很可是上线前还是出现了严重的生产事故。后来复盘发现所有的用例只测了正常扣款流程完全没人测余额不足、重复支付、超时回滚、字段缺失这些异常分支。自动化测试的价值其实不在于验证“系统能做它该做的事”而在于验证“当事情变糟糕时系统会不会优雅地处理”。只写快乐路径等于把最容易出错的那一半逻辑完全留给了生产环境去发现。怎么破我的建议是给每个“功能点”至少配两个维度的用例正面用例验证主流程能正常走通。反面用例验证异常分支能被捕获、提示、回滚或容错。还有个更细节的小技巧写用例时要习惯性地问自己“如果这里返回超时怎么办”“如果这条数据已经存在怎么办”“如果用户连点两次提交怎么办”。不要觉得这是在抬杠边界条件恰恰是线上故障的第一来源。2.3 错误三用例筛选拍脑袋把不该自动化的东西塞进脚本第三个设计期的常犯错误是自动化用例的选择完全没有流程和标准。常见的操作是领导一拍板说“我们要上自动化测试”然后团队把手工测试用例里看着最顺眼的几百条直接拿过来照着录成脚本。我的评价只有四个字自寻死路。不是所有手工用例都适合自动化。我在项目里筛选自动化用例时一般会从四个维度打分维度说明不适合自动化的信号执行频率需要在每个版本回归中反复执行一个月才跑一次甚至更少的低频用例结果稳定性输入固定时预期结果是否固定依赖主观视觉判断、依赖模糊逻辑的用例环境依赖是否能在独立环境中稳定运行依赖外部服务、弱网、地理位置等不确定因素业务风险失败后对业务的影响范围低风险低影响的功能点不值得投入维护成本这套筛选逻辑做下来你会发现真正适合自动化的用例数量通常只占手工用例总数的一小部分。这完全正常。自动化的目标是“用最少成本守住最重要的功能”而不是“把所有手工用例都翻译成脚本”。我还见过一种反向错误团队自动化了半天只挑最稳定、最简单、永远不会出问题的用例来做比如登录、退出、改个密码结果覆盖率数字很好看实际风险一点没降低。这类跑得再绿也没有价值。选自动化用例的核心原则就一条优先选那些“出了问题会死人、但流程本身又很固定”的场景。3. 写代码时埋下的三个雷一碰就炸3.1 错误四测试代码跟页面结构死死绑在一起重构就等于重写设计期的问题没想清楚后面写代码的时候通常就会在实现细节上继续犯错。其中最让团队头大的是“页面结构耦合”。什么叫页面结构耦合就是你的测试选择器表达式直接写死在脚本里而且依赖的是页面最细节的实现。比如某些团队写自动化时喜欢靠元素的绝对位置或者复杂 XPath 去定位像下面这样# 反面案例和浏览器结构强绑定的写法 driver.find_element(By.XPATH, /html/body/div[2]/div[3]/form/div[1]/input)这种写法看着能用但只要开发人员在页面前面加了一个div或者调整了一下列表结构你的定位就失效了。前端代码只要做一次正常重构测试脚本就得跟着改几十处。时间一长测试代码的维护成本甚至超过了产品代码本身。正确的姿势是分层。UI 测试代码理论上应该和页面实现彻底解耦你只应该关心“页面上有什么业务元素”而不应该关心“这个元素在 DOM 里处于什么位置”。我建议团队在写 UI 自动化时强制使用 Page Object 模式。Page Object 的核心思想是把每个页面的元素定位和操作方法封装成一个独立的类。测试用例调用的方法而不是元素本身。这样即使前端改了样式和结构你也只需要修改对应页面的类而不需要动几百个用例。好的定位策略优先级我一般这样排使用业务语义的># 显式等待的正确姿势 from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By # 等待登录按钮处于可点击状态最多等 10 秒每 500 毫秒轮询一次 login_button WebDriverWait(driver, 10, poll_frequency0.5).until( EC.element_to_be_clickable((By.CSS_SELECTOR, .login-submit)) )需要注意显式等待虽然好用但“等待条件”也得选对。很多同学喜欢等“元素存在”但元素存在并不代表它可见更不代表它可操作。等你真的点下去的时候脚本就报“element not interactable”。所以等待的条件要等到业务上真正需要的状态而不是只要能定位到就算成功。还有一个坑是前后端异步请求。页面加载完了但数据还没通过 Ajax 返回。这时候我会先等一个“页面标志元素出现”再等一个“业务数据元素出现”最后再断言。顺序很重要宁可多认识几个等待条件也不要靠堆 sleep 去碰运气。3.3 错误六用例之间相互依赖每个测试都带着前一个测试的影子代码层面的第三个大坑是测试用例没有隔离性。比如有条用例必须先走完“创建订单”流程才能测“订单支付”于是后一条用例直接调前面那条用例的函数。看起来节省了代码量实际上你已经把原本独立的两个用例焊死在一起了。这种耦合产生的典型问题包括如果“创建订单”失败了“订单支付”也会跟着失败但你根本看不出来支付功能本身有没有问题。用例只能按顺序执行无法做到数据饥饿式的并行加速。测试代码的阅读理解门槛变高了新成员根本不敢动这些“连环雷”。更严重的是有些用例依赖共享的静态数据或全局状态。比如用例 A 把系统参数改成“开启某个开关”用例 B 在没复位的情况下也去跑结果 B 失败。你排查了半天才意识到问题根本不在 B 的执行步骤里而是被前面的用例“污染”了。正确做法是每条用例都应该像是“在干净的房间里重新开始”一样每个用例独立创建自己需要的数据而不是复用上一条用例留下的数据。每个用例执行前尽可能执行环境复位或数据清理。用例之间不允许有任何调用关系公共逻辑可以抽成“助手方法”但不要用“测试用例去调用另一测试用例”的方式。这样做的代价是脚本写起来会稍微多一点但它换回来的确定性是非常值得的。毕竟测试的第一目标不是“写得少”而是“结果可信”。4. 运行维护阶段接着踩的三个坑跑起来比不跑还累4.1 错误七测试数据硬编码和共享环境跑一次脏一次运行维护期的第一个大坑是测试数据完全不可控。我见过这样的项目所有的测试用例都用同一套账号用同一个邮箱用同一个手机号。第一次跑没问题第二次跑的时候系统提示“该邮箱已被注册”于是脚本开始失败。排查了很久才发现是昨天测试自己在库里留下了脏数据。这就是典型的共享数据导致的脏环境问题。硬编码数据的危害不只是跑一次就失败更严重的是用例之间会互相干仗并行执行时冲突更是家常便饭。为了规避问题团队会加一堆“先清理再创建”的流程但这种清理逻辑本身又会成为新的不稳定点。正确的测试数据管理核心就两个字隔离。具体拆开来看有三层第一层是数据生成隔离。每个用例执行时自己动态生成独一无二的数据不会和别的用例撞车。比如往测试数据工厂里传入时间戳或随机数def generate_unique_email(prefixtest): timestamp str(int(time.time() * 1000)) return f{prefix}_{timestamp}example.com第二层是数据清理隔离。用例执行完后最好把自己创建的数据删掉或者至少标记成“可回收”。如果实在因为外键关系不能删除就要建立定期清理任务防止数据越积越多。第三层是数据环境隔离。开发环境、测试环境、预发布环境必须严格分开自动化测试不应该跑在开发人员随手造数据的公共环境里。有条件的话最好给自动化测试单独开一套环境哪怕配置低一点都行关键是环境稳定、数据可控。4.2 错误八不稳定测试混进 CI红灯变成家常便饭很多团队对自动化测试的预期是这样的脚本写完、代码里配置好、往 CI 一挂就大功告成了。实际操作起来第一个礼拜很开心从第二个礼拜开始CI 里头就开始出现各种“时好时坏”的用例。有人早上跑一次通过了下午跑一次又失败再点一次重跑又绿了。刚开始大家还会较真地去查但查来查去找不到原因。等到 CI 开始天天飘红团队的心态就变成了“这个红灯我知道是网络波动不用管”。到这一步自动化测试就已经彻底失去价值了。不稳定测试混入 CI害处不只是“多几个红点”这么简单它会摧毁整个测试体系的信任。当 CI 的红灯变成狼来了之后真正的回归缺陷也会被当作“又是那个坏用例”忽略掉。我自己在管理自动化项目时有一条铁律从不允许“不稳定”测试长时间停留在 CI 流水线里。具体执行是这样操作的同一个用例首次失败可以去查原因并重跑确认。如果同一个用例在一周内出现两次以上“偶发失败”不管有没有找到根因先把它从 CI 套件里移出移入“问题观察清单”。只有彻底修复并通过连续 10~20 次稳定运行后才允许回归主套件。这条规矩看上去很麻烦但它能逼着团队认真对待每一次偶发失败。宁可暂时少几个用例也不能让 CI 的红灯常态化。同时我还建议团队给 CI 加上“重试策略”的上限。有些团队的思路是“失败就重试三次三次都失败才算失败”这可以理解但重试本身会掩盖问题。如果用例需要靠重试才能稳定它本身就是不稳定的应该被移出而不是被纵容。4.3 错误九报告和失败信息一团糟修一个用例要半天最后一个错误也是让很多团队“做不下去自动化”的致命一击就是失败信息不可用。每次用例红了你点开日志只看到一句“expected to find elementbut not found”连截图都没有连是哪个页面的哪个操作失败都不知道。然后排查流程就变成了重新手动执行一遍用例看它卡在哪一步再根据猜想去翻产品源码最后才定位到原因。一次失败排查花掉半小时以上经历两三次之后没人想继续维护这套测试了。我一直跟团队强调一个概念测试失败报告不仅要告诉我们“哪里红了”还要尽可能告诉我们“为什么红”。这需要从源头上去做几件很朴素的事断言失败时异常信息必须包含预期的值和实际的值而不是一句笼统的“元素未找到”。比如“‘订单金额’文本显示为 99.90预期为 100.00”。UI 自动化在用例例失败时自动截图并保存页面源码有条件的话录制一段浏览器执行录像。日志里加入步骤编号和业务操作描述让人一眼能看得出来失败的是“登录后点击提交”这个动作而不是一串看不懂的函数调用栈。按模块给测试分类分组报告和趋势统计都跟着模块走不要所有用例混在一起。如果你们用的是 JUnit、TestNG 这种框架完全可以接入 Allure 或者 ReportPortal 这类报告工具把截图、录像、日志、步骤一层层挂到报告里。只花一天时间做接入后面省下的排查时间会是十个一天。5. 老鸟纠偏指南从错误清单到自查习惯5.1 给现有自动化套件做一次体检很多人读到这可能会想“完了我这套自动化项目九条几乎全占了”。也不用慌只要它还能跑就有救。我最推荐的做法是先做一次系统性体检而不是今天改一条、明天改一条最后什么都没改透。体检的清单我可以直接给出来体检项检查方法健康标准金字塔比例统计用例层级分布UI 用例不超过 30%用例价值抽样 20 条用例人工评估业务风险高风险用例占比超过一半同步策略全局搜索 sleep统计使用次数单个测试文件 sleep 不超过 2 次选择器质量统计 XPath 绝对路径和>