关于自动化测试中的反模式
dfsfds
自动化测试在软件研发中应用得已越来越广泛,自动化测试框架也变得越来越强大、可扩展,而且可以得到AI的辅助。然而,至今仍然存在各种相似的失败在各个团队间频繁出现:不稳定的测试、缓慢的调度、不稳定的定位符和脆弱的架构。
而这些问题其实很少来自于工具本身。通常,它们源于在项目中反复出现的一些特定的反模式。
因为自动化不仅仅是编写测试,它也关系到编写良好的测试、设计测试架构、考虑可维护性以及做出长期决策。但一些测试人员仍然有这些糟糕的习惯,并逐渐破坏了测试框架的可靠性。
以下我们逐步讨论一些最具破坏性的自动化反模式,并谈谈它们出现的原因、造成的影响以及如何修复。

一次性覆盖所有内容
工作中,大家应该都见过或做过这种情况:开发一个巨大的测试脚本,并试图涵盖整个用户行为路径。
这看起来没什么问题,也觉得覆盖了很多场景。但实际上,这是最大的自动化陷阱之一。
这种测试通常包括:
- 登录
- 在多个页面间导航
- 创建数据
- 编辑数据
- 删除数据
- 验证多个 UI 部分
- 登出
就好像一个线性的流水线,如果某一步失败,整个场景就崩溃了。
这些测试是:
- 极其脆弱——一个按钮的变化可能会使整个测试套件失效。
- 难以调试——你花费更多时间在调查而非修复上。
- 速度慢——迫使我们的 CI 管道缓慢运行。
- 误导性——它们给人一个虚假的覆盖感,却忽视了细节。
比如下面的例子:
| |
这个测试做了所有事情,但这正是问题所在。
要规避它的问题,我们需要做到:
- 每个测试应专注于一个特定的行为。
- 设置/清理应通过 API 或数据库完成,而不是通过 UI。
- 不要在一个场景中测试所有内容——独立测试每一部分。
这将降低复杂性,加快执行速度,并使自动化更加稳定。
随意选择定位符(比如第一个可用的)
UI 不稳定的最大来源之一是选择了错误的定位符。
很多自动化测试编写者,会抓取第一个出现的 XPath 或 CSS 选择器,将其粘贴到代码中,然后继续。这可能在最初有效,但问题是“有效”的第一个定位符往往是最脆弱的。
比如,一些不良实践可能包括:
- 15 层的完整 XPath
- 使用动态生成的 ID
- 使用与样式相关的庞大 CSS 选择器
- 使用每个 Sprint 都在变化的基于文本的定位符
- 使用基于索引的元素,如 (//button)[3]
一个例子:
| |
如果设计师移动了一个 div,那么整个case就会崩溃。
选择第一个有效的定位符是糟糕的,因为:
- 测试变得不稳定。
- 每次小的 UI 变动都会引发一系列失败。
- 我们的自动化需要不断维护。
- 新成员很难理解正在测试什么。
要解决这个问题,我们需要使用稳定、可读且长期使用的定位符,推荐的包含:
- data-testid
- 可访问性 ID
- 短小且有意义的 ID
- 可预测的 CSS 类
测试脚本开发者应该时刻与开发人员合作,改进可测试性,因为良好的自动化始于一个可测试的产品。
基于复制-粘贴的测试框架
这种情况比人们承认的更经常出现。某个 QA 急于交付自动化,因此在 1 到 2 天内草草准备一个框架,然后就立即开始编写测试。
起初,这看似“快速且高效”,但几个月后将演变为一场噩梦。
这种方法的结果通常是:
- 测试中重复代码
- 没有配置文件
- 脚本中硬编码的环境 URL
- 没有文件夹结构
- 相同的选择器和函数重复 20 次
- 没有可重用组件
- 没有抽象层
比如:
| |
某天,登录按钮发生了变化——突然间 40 个测试失败。你需要在 40 个测试中进行修改。多么可怕的维护量!
这种方法的糟糕之处在于:
- 维护变得异常缓慢。
- 小的 UI 变动需要巨大重构。
- 新的 QA 无法快速上手。
- 测试在风格、逻辑和稳定性上变得不一致。
为了避免这种噩梦,我们需要建立一个坚实的基础,以节省后面几个月的工作。我们需要投资于一个适当的自动化架构:
- 清晰的文件夹结构
- 页面对象模型或剧本模式
- 集中等待
- 全局配置和环境变量
- 可重用的助手
- 日志记录、报告和错误处理
“wait”的过度使用
这种情况也很常见
测试失败了吗?
让我们加 5 秒。
仍然失败?
让我们加 10 秒。
仍然失败?
为了保险,我们加 20 秒。
经典例子
| |
突然间,整个测试套件每天要多花 30 分钟。
这是一种非常糟糕的做法,因为:
- 它大幅增加了执行时间。
- 使测试的通过更多是侥幸而非准确。
- 隐藏了应用中的真实性能问题。
- 使调试变得更加困难。
- 产生了对测试稳定性的虚假信心。
我们应始终等待某个条件,而不是无所事事地等待。要修复这个反模式,我们需要使用:
- 显式等待
- 基于条件的等待
- 元素状态检查
- 使用 API 轮询而非 UI 等待
- 现代 AI 框架的视觉等待
自动化一切
100% 的自动化覆盖绝对不应该是我们的目标。有些场景的测试变动过于频繁,稳定性不足,复杂而无法自动化,或者没有真正的业务价值,或者需要真实的人工判断。这些场景不应纳入我们的自动化测试套件。
此外,还有一些场景不应该进行自动化测试:
- 针对动画的 UI 测试
- 快速变化的 UI 屏幕测试
- 非常深度的探索场景
- 一次性的罕见特性流
- 具有不一致的外部依赖的测试
如果你自动化这些场景,你将:
- 浪费时间自动化不断失败的测试
- 开始维护测试,而不是提高质量
- 得到虚假正面和虚假负面
- 花费数天修复无关紧要的测试
因此,在开始自动化某个场景之前,我们应问自己这四个简单问题:
- 测试是否稳定?
- 这个测试在三个月后还相关吗?
- 它节省了手动工作吗?
- 对于业务来说它是关键的吗?
如果答案是否定的——保持手动测试。
通过 UI 而非 API 准备数据
一些测试团队通过 UI 准备所有测试数据。这包括创建用户、上传文件、更新设置、设置环境状态等。每一个这样的步骤都会让我们的 UI 测试变得更慢、更脆弱。
这不是一个好的做法,因为 UI 是最慢和最脆弱的层次。此外,通过 UI 进行这些操作会引入不必要的步骤,从而增加测试的不稳定性。API 或数据直接通过数据库准备会更简单、更快速。
为避免此问题,好的做法是:
- 通过 API 创建测试数据
- 通过 API 或数据库清理
- 仅在实际行为验证时使用 UI
忽视不稳定测试
我们已经讨论过不稳定测试。它们通常存在于不稳定的定位符、错误的等待、不一致的环境、UI 中的竞争条件、破损的测试数据设置或第三方依赖之中。
每当我们注意到不稳定测试时,不应忽视它们。我们应该将不稳定性视为 P1 级别的错误。
一旦我们发现了不稳定的测试,我们应:
- 跟踪每个测试的不稳定性
- 使用仪表板或标签监控不稳定测试
- 关注根本原因
- 不依赖重试来“隐藏”问题
没有稳定性的自动化不是自动化——而是混乱。
仅在一个浏览器或设备上测试
如果我们只在 Chrome 上运行所有测试,只在一个 Android 设备上,或者只在一个 iOS 模拟器上,这就不够了,因为用户无处不在。用户使用 Safari、不同的 iPhone、可折叠的 Android 设备、高分辨率平板电脑、深色模式等。
如果我们仅使用一个设备,则Bug 可以出现在自动化未触及的设备上,浏览器特定的 Bug 可能会溜入生产环境,布局问题可能会在真实设备上出现,而我们的自动化测试可能会给我们带来虚假的安全感。
为避免此问题,我们应始终根据产品的需求创建测试矩阵,例如:
- Chrome + Safari(最少)
- 一台真实的 Android 设备
- 一台真实的 iPhone
- 明亮模式 + 深色模式
- 至少 2 到 3 种屏幕大小

这能早点发现 UI 问题并提升信心。
依赖 CI 而不在本地运行任何东西
我们不应将 CI 管道作为个人调试环境,不应直接将代码推送到管道并寄希望于最好的结果。
这不是一个好的做法,因为它可能会阻塞整个管道,破坏主分支,减慢整个团队的速度,并且会使调试更加困难,因为 CI 所需时间更长。
为避免这些问题,我们应始终:
- 在将更改推送到管道之前,确认本地测试可正常运行。
- 在本地运行小部分测试
- 将完整回归测试留给 CI,但自己测试基础功能
没有日志、没有截图、没有跟踪
我们的测试应提供丰富的结果信息,而不仅仅是“通过/失败”的状态。一些框架不保存截图、不捕获控制台日志、不录制视频、不收集网络跟踪,不会生成清晰报告,使调试更加困难和复杂。
我们应始终研究我们框架的可能性,也许使用一些额外的插件、HTML 报告器或第三方工具来生成这些对我们测试结果有价值的信息。这些信息对我们 QA 来说非常重要,对整个团队和其它利益相关者也是如此。
结语
如你所见,这些例子中,最大的自动化失败通常是由快速决策、不良习惯和缺乏结构导致的。
通过避免这些反模式,我们的自动化测试套件将更加稳定、可维护、快速、可靠,并受到团队的信任。
自动化需要规划和纪律,而不仅仅是工具。
