单位 9 / 11

回归测试、测试维护和对抗脆弱测试

收益:

  • 了解回归测试的目的,并能够根据人工智能的变化选择测试并产生回归案例
  • 能够诊断脆弱测试的根本原因(时序、顺序依赖性、共享状态、外部依赖性)并应用永久解决方案而不抑制症状
  • 能够维持运行完整包预发布的纪律,同时通过消除重复测试来保持回归套件快速、独立和可靠

软件不断变化;每个新功能、每个修复都可能会破坏以前有效的功能。随后对先前工作功能的破坏称为回归。回归测试是通过每次更改重新测试现有功能以捕获这些降级。随着时间的推移,这些测试套件变得越来越大(成千上万的测试),并且出现了两个大问题:套件速度变慢,而不稳定的测试(在同一代码中有时通过有时失败的不可靠测试)破坏了团队对测试结果的信心。人工智能 (AI) 是保持回归套件维护良好、快速且可靠的强大帮助。但核心警告仍然存在:虽然人工智能可能会“通过”脆弱的测试,但它通常可以生成一个补丁来掩盖真正的错误。你的工作是找到不稳定的根本原因,而不是抑制症状。

脆弱测试的根本原因

脆弱测试是最阴险的测试问题:无论通过还是失败都是不可靠的,迫使团队养成“肯定又卡住了,再运行一次”的习惯——而这种习惯有一天会忽略一个真正的 bug,认为它是“脆弱的”。主要根本原因:

  • 计时/竞争条件:测试无需等待操作完成即可检查结果。最常见的原因。
  • 顺序依赖:测试依赖于彼此留下的数据;当顺序改变时它就会中断。
  • 共享案例:多个测试使用相同的测试数据/用户,存在冲突。
  • 外部依赖:真实网络、第三方服务、系统时间、随机值。
  • 环境差异:切换到本地,停留在CI(持续集成环境)。
注意:通过“重试几次”来通过脆弱的测试通常会掩盖真正的并发错误。重试是一种诊断工具,而不是治疗方法。首先找到根本原因;仅将重试作为记录的、真正的外部不稳定的最后手段。

测试维护:保持包装健康

回归套件就像一个花园;如果不加以照顾,杂草就会占据上风。人工智能协助完成三项维护任务:

1. 重复/不必要的测试清洁。随着时间的推移,大量的案例积累测试同样的事情。人工智能建议对类似的测试进行分组和合并。

2. 脆弱的测试诊断。你给AI测试代码和不稳定模式;提出可能的根本原因和永久解决方案。

3. 测试选择/优先级排序。每次更改都运行整个包的成本很高。通过测试影响分析(根据更改的代码仅选择相关测试),AI 会建议应首先运行哪些测试。然而,完整的预发布包是必须的。

检疫:管理脆弱的测试权

您发现测试很脆弱,但您没有时间立即解决根本原因。该怎么办?有两种错误的方法:完全删除测试(根本不再保留该行为)或通过重试使其安静(掩盖真正的错误)。正确的方法是隔离(暂时将易碎测试与主包分开,并在单独的列表中进行跟踪)。隔离测试不会阻止版本合并,但仍然是一个明显的债务并定期得到解决。关键是:隔离区是候诊室,而不是垃圾桶。如果隔离名单不断增加,则表明团队的测试健康状况正在恶化。人工智能可以定期审查您的隔离列表,并按根本原因模式对其进行分组;它通过揭示常见原因(例如“所有 6 个测试都连接到同一个共享测试用户”)来实现集体解决方案。

提示:为每个隔离记录添加“所有者”和“上次查看日期”。废弃的检疫区变成永久垃圾场;脆弱的测试永远存在,因为没有人关心。

回归策略表

状态

策略

人工智能的作用

小修正

受影响区域+烟雾测试

选择相关测试

新功能

相关模块+集成

提出一个新的回归案例

大重构

完整回归包

覆盖差距分析

预发布

全套+探索

优先级和持续时间估计

紧急实时修复

重点+关键路径

最小安全测试集

弱提示/强提示

弱:“这个测试有时会失败,修复它。”
强:“此测试在 10 次运行中失败 3 次,代码不变。诊断不稳定的根本原因:可能是计时/竞争、顺序依赖性、共享状态、外部依赖性或环境差异。显示测试中的哪一行指向每个可能的原因。建议永久解决方案;不要建议症状抑制解决方案,例如“添加重试”——如果不可避免,请写清楚原因。测试:[代码]。错误跟踪:[日志]。”

强大的提示功能;将诊断引导至根本原因并明确禁止症状抑制。

四个可复制模板

1)脆性测试诊断:

该测试代码有时通过,有时失败,无需更改。列出候选根本原因(竞争、顺序依赖性、共享状态、外部依赖性、时钟/随机、环境差异),并在每个问题的测试中显示证据线。建议永久解决方案;将重试等抑制性解决方案标记为最后手段并提供理由。测试:[代码]/不稳定模式:[多少次运行中有多少次]

2)提出回归案例:

进行了以下更改:[更改/PR 摘要]。列出此更改将破坏的当前行为,并为每个行为提出回归测试用例。特别强调副作用和共享依赖性的领域。

3)重复测试清理:

查看下面的测试套件。将测试相同行为的重复或重叠案例分组;建议我应该保留哪些以及应该为每个组合并哪些。如果存在失去承保范围的风险,请发出警告。测试:[列表/代码]

4)测试效果选择:

以下文件/功能已更改:[列表]。从现有的测试套件中,选择并证明我需要首先运行的测试(那些直接/间接链接到更改的代码的测试)。注意:提醒我,我仍然会运行完整的预发布套件。

三个迷你箱子

案例 1 — 重试掩盖了真正的错误。一个团队在偶尔的剩余支付测试中增加了 3 次重试;现在测试总是“通过”。应用“脆弱测试诊断”发现不稳定来自于真实的竞争条件:在高负载下,支付确认有时会被双重处理。几个月来,Retry 掩盖了一个可能导致实际金钱损失的错误。根本原因已修复,重试已删除。

案例 2 — 封装缩小,速度提高。包含 1,400 个测试的回归套件耗时 55 分钟。通过“重复测试清理”,380个测试结果被重复或覆盖;合并了。包测试次数减少到 900 次,时间减少到 34 分钟,覆盖范围没有明显减少。更快的反馈鼓励团队更频繁地进行测试。

情况 3 — 订单依赖性。测试在本地总是会通过,但在 CI 中会随机失败。 AI 诊断表明该测试依赖于另一个测试创建的用户,在 CI 中它失败了,因为测试以并行/不同的顺序运行。每项测试都是为了建立自己的数据;犹豫不决已经结束了。

常见错误

  • 通过重试来静默脆弱的测试。不寻找根本原因就重试;掩盖真正的错误。
  • “再次卡住”文化。通常忽略红色结果;有一天,跳过了真正的错误。
  • 根本没有修剪包。允许重复的测试堆积并减慢包的速度。
  • 测试之间的依赖性。测试基于常见条件/顺序;不确定性的来源。
  • 仅测试更改的部分并跳过整个包。预发布快捷方式;隐藏的副作用逃脱了。
  • 依靠外部依赖。基于实际网络/时钟/随机值进行测试;自然不稳定。

总之

回归测试捕捉到破坏之前工作功能的变化;但随着软件包的增长,缓慢且脆弱的测试会侵蚀信任。脆弱测试的根本原因通常是时序、顺序依赖性、共享状态和外部依赖性。人工智能在诊断、清洁和测试选择方面具有强大的帮助;但通过重试来抑制优柔寡断会掩盖真正的错误。找到根本原因,使测试独立且具有确定性,定期修剪软件包,在发布前运行完整的软件包。

应用任务

从您自己的项目中选择一个您知道很脆弱(或看起来不稳定)的测试。使用“脆弱测试诊断”模板提取候选根本原因并验证测试中的证据线。找出根本原因并实施永久解决方案,而无需重试。然后从包中选择 10 个测试,并找到那些可以与“重复测试清理”结合使用的测试。报告您从根本原因解决了多少测试不稳定性,以及您从套件中删除了多少不必要的案例。

清单

  • [ ] 我已经诊断出脆弱测试的根本原因;我没有抑制这个症状。
  • [ ] 我认为重试是合理的最后手段,而不是治愈方法。
  • [ ] 我使测试变得独立且具有确定性(与外部依赖项隔离)。
  • [ ] 我从回归套件中删除了重复/不必要的测试。
  • [ ] 我选择根据更改进行测试,但运行了完整的包预发布。
  • [ ] 我认真对待每一个红色,反对“再卡住,就通过”的文化。