大多数 QA 工程师在回答这个面试题时,基本都答错了。下面说说“当 UI 测试不稳定时,你会停止做什么?”这背后实际上在考察什么,以及什么样的回答是有经验的。
最近,一个关于面试题的帖子发在 QA 论坛上,它引发了广泛讨论:
“当 UI 测试不稳定时,你会停止做什么?”
这个提问措辞会让人栽跟头。大多数面试题问的是你会做什么,本质上是你的流程是什么、你如何处理、你会拿起哪些工具。这个问题反过来了。它问的是要消除哪些习惯,这意味着面试官已经假设你有这些习惯。而且,它或许是有意这样。
我在软件测试领域有 20 多年经验,覆盖金融科技、SaaS HCM 和保险科技,目前担任所在公司的质量工程总监。我没有被完全相同的措辞问过这个问题,但我作为面试官用过类似问题,所以我知道这类问题旨在挖掘什么。
在给出答案之前,我们先看看 QA 社区怎么说。
调查结果图片如下:
显示所有答案
社区中最受欢迎的回答既技术化又容易共鸣——停止使用 sleep() 、修复时序和等待——这是任何花时间调试过间歇性失败的人的本能反应。“先调查根本原因”按数量排名较低,但得到了那些停下来思考“实际被问的是什么”的人最多的赞同。
我还在 LinkedIn 上发起了同样问题的投票。它获得了 357 次展示,却只有 5 票——参与度很低——但这 5 位投票者一致选择了“先调查根本原因”。自由评论的社区投票模式与强制选择投票结果之间的差距本身就说明问题:当人们必须只选一个答案时,他们选择了诊断式方法;而在自由评论时,他们先讲最贴近自身经历的踩坑故事。
为什么大多数候选人答错了问题
值得停下来思考的是:社区里许多最受欢迎的回答——包括从 CI 中隔离测试、添加重试逻辑、向开发团队报告不稳定——都是对“你会如何处理不稳定测试”的有效回答。它们不是对“你会停止做什么”的回答。
隔离是你添加到流程中的动作。重试是你实现的东西。报告是你开始做的事情。这些都不是你要停止的事情。
社区自己的讨论恰好展示了这个问题旨在暴露的失败模式:回答了另一个问题,而不是被问的问题。
在面试中,这值得有意识地停一下。在开始回答前,复述问题:“所以您问的是我会停止哪些习惯——而不是我会在流程中增加什么?”这一句话表明你在压力下依然精确,而精确很重要。
当我进行面试时,如果候选人的回答感觉不对,我会请他们复述自己对问题的理解。有时他们就是答错了,但更常见的是,他们因为紧张、语言障碍,或者在远程面试中音频丢包,而没有在当下完全处理问题。面试处理得最好的候选人,是那些在回答前预先复述自己理解的人。这显得既自信又谨慎(对测试人员和质量工程师来说都是好品质)。
这个关于不稳定测试的面试题实际上在考察什么
这个问题至少同时考察四件事:
-
• 技术知识 ——你是否了解导致 UI 测试不稳定的常见反模式? -
• 诊断思维 ——你能否推理根本原因,而不是背诵修复清单? -
• 听力理解 ——你是否真的处理了被问到的问题? -
• 挑战模糊表述的信心 ——候选人会接受措辞别扭的问题,还是指出它并请求澄清?
初级回答会列出战术:停止使用 sleep ,修复等待,添加重试。没有错,但停留在症状层面。
有经验的回答会叙述一个思考过程——你会如何先识别导致不稳定的原因,再决定改变什么。“停止做什么”这个框架就是线索。它问的是你已经不得不摒弃哪些习惯,暗示你曾在足够大的规模下工作,并通过惨痛教训学到了它们。
当 UI 测试不稳定时应该停止做什么:完整回答
如果面试中被问到这个问题,我会先澄清框架:“你问的是导致不稳定的常见反模式,还是更多问我如何开展调查?”这个区分很重要,问出来本身就表明,在答案开始前你就在进行诊断式思考。
如果他们想要方法角度,我会这样回答。
停止向不稳定的测试套件中添加测试
这会是我的第一个答案,我也会先讲它。
向不稳定的套件中添加测试会加剧问题。每个新测试都会继承其运行环境的不稳定性。在扩大覆盖率之前,你需要先止血,并理解不稳定存在于测试代码、应用行为还是基础设施中。这个区分决定修复的形态。
停止使用 sleep() 和 pause 语句
这是最能引发社区一致赞同的回答,而且理由充分——它是 UI 测试自动化中最普遍的不良习惯。
sleep() 和 pause 是粗暴工具。它们会等待固定时间,不管所等待的条件是在一秒内变为真,还是根本不会变为真。它们缓慢、脆弱,并掩盖真正问题:测试不知道自己在等什么。
这一点已经被充分认识,以至于 Playwright 在自己的 API 文档中正式将 page.waitForTimeout() 标记为“不推荐”:
“永远不要在生产环境中等待超时。依赖时间等待的测试天然不稳定。请使用会自动等待的 Locator 操作和 Web 断言。”
Playwright 文档——
page.waitForTimeout()
我曾在我管理的测试套件中强制移除 pause 语句,并用显式等待模式替代—— waitForElementPresent 、自定义轮询等待——任何在条件为真时立即返回、而不是等完固定间隔的方式。我还添加了 lint 规则,防止 .pause 命令被提交进来。在一个大型串行套件中,仅移除 sleep 和 pause 语句就使总测试运行时间减少了一个多小时。
一个实践细节:设置最大等待超时时,我会把它设为大约我预期最坏情况的两倍。CI 环境一贯比本地开发运行得慢,而且方式并不总是可预测。在本地看起来足够宽松的等待,在 CI 负载下可能超时。
停止假设问题出在测试代码中
有些不稳定根本不在测试里。
我有一个测试会根据构建在一天中的什么时间启动而间歇性失败。调查后,根本原因是被测服务器和运行测试的系统之间的时区不匹配。由于这个偏移,应用中的一条验证规则在某个特定小时表现不同——测试忠实地捕获了真实行为,但直到你足够仔细地看,它才像是随机不稳定。最初调查很棘手,因为当我们一开始尝试复现失败时,它在正常工作时间会通过!
修复是在测试中加一个条件分支,以处理那个魔法时刻的业务规则。我通常避免在测试中使用条件分支逻辑——它增加复杂性,让测试更难推理。但我们无法时间旅行或更改系统时钟,条件分支是诚实的解决方案。
要点:在假设测试坏了之前,先确定你面对的是测试代码、应用缺陷,还是基础设施不匹配。每种情况的调查方法都不同。
还值得注意的是,有些间歇性失败根本不是不稳定——而是测试捕获了应用中真实的间歇性缺陷。一个测试失败一次、下次重跑通过,表面上看与不稳定测试完全相同。一个是噪声;另一个是你即将忽略的信号。这就是为什么每次失败在被打发掉之前都值得调查。
目标是让套件足够可信,以至于测试失败时团队的第一反应是“它发现了问题”——而不是“唉,又不稳定,重跑一下”。一旦重跑成为默认反应,它就会变成凌晨3点烦人的汽车警报,而不是有用的工具。
停止在未隔离共享状态的情况下并行运行测试
并行化值得追求——大型套件节省的时间很显著,而且这是你能对 CI 反馈时间做出的最高杠杆改进之一。问题不在并行化本身;而在于并行运行那些从未为此设计的测试。
共享数据、数据库状态或外部资源的测试,一旦并行化,就会变得依赖顺序、依赖环境。一个串行运行干净的套件,在并行时可能看起来严重不稳定,而且没有明显原因——因为不稳定存在于测试之间的交互中,而不是任何单个测试中。
实际解决方案是停止把套件当成单一同质运行,开始思考哪些可以安全并发运行:
-
• 只读测试 ——只查询状态而不修改状态的测试——是并行执行的天然候选。它们不会相互干扰。 -
• 写操作、依赖状态的流程,以及任何接触共享 fixture 的东西 ,最好留在串行套件中,直到你妥善隔离了它们的数据(每次运行唯一测试数据、专用测试账户、隔离环境)。
组合方法——对安全测试用并行套件,其余用串行套件——可以让你获得大部分速度收益,同时保持不稳定面很小。一旦串行测试用它们自己的数据妥善隔离,就可以逐步把它们升级到并行套件中。
停止把不稳定性当作正常现象
团队对不稳定测试能做的最有害的事情就是耸耸肩接受它。
不稳定性训练所有人忽略失败。一旦构建变成噪声生成器而不是信号,真实回归就会不受质疑地溜过去。一个喊“狼来了”的测试套件,在功能上比没有测试套件更糟,因为它制造虚假信心。
我曾在 BitBucket 和 BrowserStack Test Analytics 中使用不稳定性评分来识别并静音最严重的罪魁祸首。静音不同于删除:测试仍会运行,只是在调查期间不会让构建失败。这个区别很重要——它保留了跟踪改进是否有效的能力,同时不让不稳定在此期间污染每个构建。
如何回答 UI 测试不稳定的面试题
无论你如何组织答案,都有几个框架性提示:
-
• 先复述。 在深入之前,确认你理解了问题。“所以您问的是我会停止哪些习惯,而不是我会在流程中增加什么?”一句确认展示仔细倾听——这可以说是这个问题最想考察的。 -
• 叙述,不要罗列。 一串战术听起来像你背了清单。一个思考过程——“我会先确定这是测试代码、应用行为还是环境,因为每种修复方式不同”——听起来像真正大规模处理过这个问题的人。 -
• 区分问题类型。 并非所有不稳定性都有相同根因。时序问题、共享状态、环境不一致,以及自动化不稳定的 UI,是四个不同问题,有四种不同修复。展示你能区分它们,是好的回答和更有经验的回答之间的差别。 -
• 讲一个具体例子。 最令人难忘的面试回答是具体的。如果你重构过满是 sleep语句的套件,或追踪过一个看起来像随机不稳定、持续数周的时区不匹配,就说出来。具体经验比听起来正确的泛泛之谈更可信。

