基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
AIHT
内容
精选全部 AI 动态热点榜AI 日报收藏
分类
模型行业编程产品技术观点开源
更多
Agent 接入
返回首页开发者导航
AIHT
精选 / 资讯详情
8.0
热点
AI SCORE
编程提效2026-10-30 11:32

用回归测试防止编程智能体重犯旧错

dev.to · AI#AI编程#回归测试#持续集成
Editor brief · 编辑速览

编程智能体跨会话缺乏修复背景,可能在重构时删除保护逻辑,让旧缺陷再次出现。文章建议将每次修复固化为纳入版本控制和 CI 的回归测试,用可执行断言保留约束。

文章思维导图
Knowledge map
拖拽缩放
AI deep read

AI 深度解读

AI 刚修好的 bug,换个会话、做次重构,为什么又回来了?作者给出的解释是:新会话能看到当前代码,却未必知道某段防御逻辑当初为什么存在。看起来多余的判断,可能正是上次事故留下的修复。

作者的主张很明确:把修复原因变成仓库里的回归测试,让旧问题一回来就触发构建失败。对日常使用 AI 改代码的程序员,这篇最有用的地方,是区分了三种复发原因,以及各自应该补在哪一层的保护。

同一个 bug 回来,可能是三种不同的问题

原文用支付接口举例:3 月修复了重复扣款,6 月一次无关重构又把它带回来。这个故事用于说明风险,作者没有提供对应项目、事故记录或发生频率,不能当成实测数据。

第一种情况是,修复理由只留在聊天里。

代码里留下了空值检查、重试上限,或者先排序再去重的处理,但没有留下约束的来源。下一次会话只看到最终写法,可能把这些步骤视为冗余。修复结果进了仓库,推理过程却停在聊天记录中。

第二种情况是,保护逻辑还在,却没有测试。

例如,注释写着 // do not remove: prevents duplicate charges。它提醒后来者不要删除,但无法阻止构建通过。AI 重新生成函数时,可能保留注释却漏掉保护机制,也可能一起删掉。

第三种更隐蔽:修复依赖的结构变了。

原来的正确性可能来自某一层处理幂等键、两次写入共用一个事务,或者队列负责事件去重。重构把逻辑移到其他层,即使没有修改最初修复的代码,也可能破坏这些条件。旧函数的单元测试仍然通过,整条业务路径却已经出错。

这三种情况不能只靠一句「下次记住」解决。前两种需要把隐含要求变成可执行检查,第三种还需要重新确认检查覆盖的边界。

测试要守住业务结果,不能只盯着函数写法

作者反复强调一个词:不变量(invariant)。它指的是,无论代码怎么组织,都必须成立的条件。例如,同一个幂等键不能产生第二次扣款。

回归测试应该锁住不能出错的结果,而不是某次修复的具体写法。

因此,测试名称应该表达「同一个幂等键不会再次扣款」,而不是「调用一次 dedupeHelper」。后者绑定了内部实现;换个辅助函数、移动一次逻辑,测试就可能需要重写,却未必更能保护用户。

断言也一样。原文建议检查可观察结果,例如只发生一次支付捕获操作、返回相同标识,而不是只检查某个内部 helper 被调用了几次。

不过,写出一个绿灯测试还不够。作者要求先证明它能复现旧问题,再验证修复后通过,也就是先红后绿。否则,测试可能只是碰巧通过,根本没有触发事故条件。

对于跨层问题,作者建议增加端到端检查。原因很直接:如果正确性来自接口、事务或队列之间的配合,只测其中一个函数,无法证明配合关系仍然成立。检查需要走过相关路径,再断言最终结果。

原文还提到另一类保护:由 OpenAPI 文档生成类型,或者通过 schema 校验响应结构。字段不能是 undefined、响应必须符合契约,这类要求适合交给类型和结构检查,让约束随着代码一起被读取。

一次修复,要交付哪些东西才算结束

作者建议,在同一个提交中放入修复代码、能捕获旧问题的回归测试;如果约束不直观,再补一句解释原因的注释。

这里的顺序很重要:先证明测试有用,再把 bug 标记为已解决。

原文提出两种验证办法。一种是把新测试放到修复前的代码上运行,确认它会失败;另一种是在临时分支里主动撤回修复,观察是否出现红灯,再丢弃这个分支。如果没有任何测试失败,就说明现有测试尚未证明能保护这次修复,无论旁边写了多少解释。

更长的上下文、上传完整历史,作者认为能降低复发概率,但不能提供同样的约束。上下文会被截断或压缩,原来的推理在结构变化后也可能失效。历史适合帮助理解,构建检查负责在条件被破坏时给出信号。

外部 API 也可以采用类似思路:根据 OpenAPI 文档或录制的响应样本建立契约测试,把依赖的响应结构明确写下来。不过,原文没有展开这些输入如何更新,这一点会直接影响检查能发现什么。

我的判断

我赞同把修复沉淀成可执行约束。它对 AI 和人类开发者都有效,尤其适合那些代码看起来可以简化、实际却有业务原因的地方。相比反复补提示词,这种做法更容易进入代码审查和日常构建流程。

但原文有几处说得偏满。

作者称,把它设为合并要求的团队就不再遇到旧 bug 复发,还把投入描述为「修复时多花几分钟,省下以后几小时」。文章没有给出团队样本、统计口径或对照数据,这些只能看作经验判断。

测试也不是自动生效的围栏。它需要被 CI 执行,失败需要阻止合并,测试本身被删除或削弱时也需要审查。AI 同样能修改测试,红灯并不天然不可绕过。

类型和契约检查也各有边界。生成类型适合约束代码中的字段使用,却不能单独证明外部响应真的符合类型;固定 fixture 能保护解析逻辑,但上游已经变更时,旧样本仍可能让测试通过。要发现真实变化,还需要相应的契约更新或边界验证机制。

此外,跨层问题需要覆盖业务边界,并不代表每次都必须启动完整端到端环境。能稳定覆盖事务、队列或接口协作的集成测试,也可能满足目标。选择依据应该是故障发生在哪里。

能拿来做什么

  • 下次让 AI 修复 bug 时,把验收要求写成「提交一个在修复前失败、修复后通过的测试」,并检查它断言的是用户可见结果。
  • 对前端或 Node 项目里难以理解的空值判断、重试上限和去重顺序,先找对应测试;没有覆盖时,补上原始失败场景,再考虑简化代码。
  • 重构接口处理、事务或队列逻辑前,确认现有测试是否穿过相关边界,避免只验证单个函数仍然正常。
  • 依赖外部 API 响应结构时,把字段假设落实到契约检查中,同时明确 OpenAPI 文档或 fixture 的更新方式。
Original source

本文由 AI 通读原文后重新编写,观点部分为站内判断,细节以原文为准,来源 dev.to · AI,原文版权归原作者所有。

阅读原文
上一篇
Agent 接口如何支持断线恢复与幂等写入
下一篇
Node.js 语音转写如何处理服务不可用

资讯速览

dev.to · AI · 2026-10-30 11:32

AI 评分 8.0 / 10

相关标签

#AI编程#回归测试#持续集成

继续阅读

  • LLM JSON 接入生产:结构约束与异常处理
  • Agent 接口如何支持断线恢复与幂等写入
  • Node.js 语音转写如何处理服务不可用
  • 浏览器本地转写的线程与取消机制
  • 自部署会议转写:从音频到说话人字幕