2026年10月20日

使用 AI 编程时,测试何时才算足够?永远不会

使用 AI 编程时,测试何时才算足够?永远不会

AI 可以在几分钟内生成数千行代码。但谁来验证这些代码每一行真的可以正常运行?

没有人。

随着 AI 越来越多地参与到软件开发中,有一个问题不断浮现:我们什么时候才算写了足够多的测试?

我的答案很简单:永远不会。而在 AI 生成代码的时代,这个答案每天都变得更加贴切。

AI 改变了开发的速度,却没有改变对正确性的需求

编写代码已经不再是软件开发中最耗时的部分。AI 编程助手以惊人的速度生成函数、API、数据库迁移、基础设施配置乃至整个应用程序。过去需要几天的工作,现在可能只需几小时。有时甚至几分钟。

问题出在方程式的另一半。AI 生成代码的速度,远快于人类理解、审查和验证它的速度,这造成了一种失衡。我们生成得越快,就越容易引入缺陷、安全漏洞、错误的假设以及意料之外的行为。AI 并不会消除软件缺陷。它消除的是延缓缺陷出现的阻力。

更糟的是,AI 生成的代码通常看起来很有说服力。它很整洁,结构清晰,注释充分,看上去逻辑严密。直到它在生产环境中真正跑起来。

每一行代码都是潜在的失败点

每一行有意义的 AI 生成代码,都应当由自动化测试来验证。不是只测关键函数,不是只测正常路径,也不是只测 AI 恰好想到的场景。每一行、每一个分支、每一个条件、每一个异常,都应当被覆盖。

逐字面行为一行配一个测试,并不是一种实用的测试策略。一个测试可以覆盖很多行,而完全的行覆盖率也不能保证正确性。但门槛应当高于通常意义上的覆盖率:我们需要验证代码做了什么,而不仅仅是确认它执行过。

以一个支付函数为例。它在输入合法时工作正常。但当网络中途失败、当同一个请求被提交两次、当交易被打断、当响应携带意外的数据、当两个请求同时到达、当 API 返回一个无人预料的错误时,会发生什么?

十个通过通过的测试,覆盖不了第十一种场景。测试只证明了那些已经检查过的行为。它们无法证明那些无人想到的缺陷并不存在。

测试必须每次都运行

自动化测试不能是偶尔才运行一次的东西。不是在冲刺结束的时候,不是在重要发布之前,也不是在我们想起来的时候。在 AI 辅助开发的今天,自动化测试是持续运行的。每一次有意义的代码变更,都会触发相应的测试,全量回归套件会在既定的集成关口和发布关口运行。

原因在于爆炸半径。一次看似微小的 AI 生成变更,其影响范围可能远远超出它所修改的那个函数。一个智能体可能在修复某个模块缺陷的同时,弄坏了另外三个模块;可能更新了一个依赖项,修改了一个共享接口,或者改变了某个数据库查询,而影响了毫不相关的功能。

当一个智能体报告 "实施完成,所有请求的变更都已完成" 时,这句话几乎不能说明任何关于正确性的信息。代码的完成并不等于验证的完成。一项任务只有当所需行为已通过有意义且自动化的检查得到独立验证之后,才算完成。而即便如此,也只是相对那些检查所能发现的失败而言,得到了验证。

永无止境的测试循环

我们写的测试越多,发现的边界情况就越多。发现的边界情况越多,需要修改的代码就越多。修改的代码越多,所需的测试就越多。然后我们再从头开始。这个循环没有天然的终点,而 AI 让这个循环变得更紧凑,因为它消除了编写代码过程中的大部分阻力。

一个智能体可以生成 500 行代码,另一个智能体可以生成相应的测试,第三个智能体可以对两者进行评审。但谁来验证这些测试本身是否正确?如果实现和测试中都潜伏着同一个有缺陷的假设,那么代码会通过、套件会全绿,而缺陷会一直留存。这正是 AI 自我测试其工作成果时最致命的局限:AI 生成的测试,可能只是在为 AI 生成的错误背书。

独立验证、对抗性测试生成、变异测试、基于属性的测试、集成测试,以及真实场景下的行为验证,是对此的制衡。即便如此,绝对的确信依然遥不可及。

全绿的测试套件不等于正确性的证明

一条全绿的上线流水线令人心安。全部测试通过。覆盖率:100%。没有报告的失败。看上去这就是成功。

但 100% 的覆盖率只意味着代码在测试所代表的那一组条件下执行过。它并不意味着代码在每一种条件下都表现正确。它并不意味着应用是安全的,不能保证并发操作是安全的,也不能说明系统能应对生产环境的流量。一个系统可以拥有完美的行覆盖率,却依然在根本上是错误的。覆盖率衡量的是我们执行过什么,而不是我们理解了什么。

因此,真正的问题不是我们有多少测试,而是我们的软件还有多少种我们未曾想到的失败方式。

AI 生成的测试应当多于代码

我们应当停止用 AI 产出多少代码来衡量它的生产力,转而以它交付了多少经过验证的功能来衡量。一百行经过充分测试、值得信赖的代码,价值胜过五千行未经验证的实现。

更大的机会在于把 AI 视作一个不懈的测试伙伴:它应当尝试去打破自己创建的软件、挑战假设、生成对抗性输入、探索边界情况、模拟失败,并质疑现有测试是否足够。然后在每次变更之后重复这一过程。生成,测试,打破,修复,再测试,重复。目标不是为测试而测试。目标是在用户发现之前,先把失败找出来。

AI 开发的成本结构正在改变

AI 降低了代码生产的成本。它并不会自动降低证明代码可靠的成本。随着生成变得越来越廉价,验证便成为软件开发中的主要成本。生成一个应用或许只需一小时,而建立起对其正确性的信心,可能需要数周。

这并不奇怪。编写软件与证明其可靠是两件不同的事情:前者创造可能性,后者系统性地消除不可接受的失败。AI 创造可能性的速度越快,验证的负担就越重。

这意味着,测试基础设施、持续集成、可复现的环境、可观测性以及自动化的安全检查,不再是次要的关注点。它们正是 AI 辅助开发的根基。

那么,测试何时才算足够?

在实践中,我们可以为一次发布建立可接受的风险水平。我们可以定义质量门槛、必需的覆盖率、安全阈值、性能要求,以及那些必须通过的业务关键场景。我们可以判定一个系统已经得到充分测试,可以发布。那是一次发布决策,而不是测试已经完成的证明。

永远还会有另一个边界情况、另一次依赖项更新、另一组意料之外的输入、另一种无人预料的生产场景、另一处 AI 生成的修改,去改变我们原本以为是稳定的东西。没有任何一项终极测试能证明,我们再也不需要写下一个测试。

代码或许可以写完,测试却永远不会结束

AI 改变了我们构建软件的速度,却没有改变软件工程的基本挑战:确保我们构建出来的东西真的能够正常运行。如果说有什么改变,那只是让这项挑战变得更加紧迫。

我所遵循的规则很简单。每一段有意义的代码都要经过测试。每一处相关的变更都会触发自动化验证。每发现一个缺陷,都要为它补上一条回归测试。每一次通过的测试套件,只是信心的证据,而非完美的证明。

永远不要因为代码是 AI 写的就信任它。永远不要因为测试是 AI 生成的就信任它。AI 辅助编程的未来,不仅在于更快地生成代码,更在于持续地、独立地、严谨地验证代码。

当有人问需要多少测试才够时,我的回答始终如一:永远不会够到可以停止测试。在软件工程中,尤其是在 AI 的时代,永远都可能再多出一样出错的地方。


#人工智能 #软件工程 #AI测试 #AI编程 #DevOps #持续测试 #软件质量 #测试自动化