登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  科技周边 >  人工智能

AI 生成代码如何用单元测试约束修改范围

来源:17golang原创

时间:2026-09-12 23:24:47 366浏览 收藏

让 AI 改一个函数时,真正难防的往往不是代码不能运行,而是它顺手重写了相邻模块、改变了未在需求里提到的默认行为。比较稳的做法是先把“允许改什么”写成修改预算,再用单元测试固定行为契约,最后把测试结果和 git diff 一起作为验收门槛。测试通过只能说明样例行为暂时成立,不能替你判断改动有没有越界。

把一次 AI 代码修改限制在“目标函数 + 明确不变量 + 最小测试集”内;定向测试和完整回归都通过后,还要检查差异文件与差异行是否仍在预算里,二者有一个不满足就退回修改。

要点速览
  • 先列出允许修改的文件、函数和不能变化的输入输出边界,再向 AI 提需求。
  • 单元测试要覆盖正常值、边界值和异常值,测试数据就是生成代码的行为护栏。
  • 把定向测试、完整回归和 git diff 分成独立检查,不能用“全绿”掩盖范围扩大。
  • 出现失败时优先缩小任务或撤回越界差异,不要让 AI 在一大段混杂改动上继续叠加。

先定义修改预算:让 AI 只动该动的地方

“帮我优化这段代码”对模型来说范围太大,也没有可判定的结束条件。更适合工程协作的请求,要同时写出目标、允许修改的位置和禁止事项。例如本次只调整 normalize_phone,允许改动 phone.py 与对应测试,不改数据库模型、不增加第三方依赖;输入为空时仍返回空字符串,非法字符仍按既有约定处理。

这里的修改预算不是提示词装饰,而是后面检查 diff 的尺子。预算至少包含三项:目标符号、允许文件、必须保持的行为。如果需求本身还没有说清楚异常值怎么处理,就先补问题,不要把决定权交给生成结果。

AI 生成代码的修改预算、不变量、单元测试和生成代码关系示意图
图1:AI 代码修改的契约关系示意图,先用修改预算和单元测试圈定可接受范围。

用单元测试把行为契约固定下来

测试不是为了证明 AI 写得漂亮,而是把读者真正关心的行为变成可重复判断。以手机号清洗为例,至少要准备普通输入、带空格和短横线的输入、空值以及不应被悄悄改写的格式。pytest 的参数化测试适合把同一规则放进多组输入中,避免只测一个“看起来正常”的例子。

import pytest

@pytest.mark.parametrize("raw, expected", [
    ("138 0013-8000", "13800138000"),  # 普通分隔符应被清除
    ("", ""),                            # 空输入保持原有空值语义
    ("+86 13800138000", "+8613800138000"),  # 国家码不能被误删
])
def test_normalize_phone(raw, expected):
    # 只锁定公开行为;具体实现仍允许在预算内调整
    assert normalize_phone(raw) == expected

先运行基线测试,确认测试本身能反映当前契约。再把测试命令、目标函数和禁止事项放进 AI 请求中,并要求它先说明计划、只提交一个小改动。测试用例应尽量独立于网络、时间和真实账号,否则失败时很难判断是生成代码的问题,还是外部依赖抖动。

把生成任务切成可验收的小改动

一次请求最好只解决一个问题,例如“在不改变返回格式的前提下,支持空格和短横线”。不要同时要求重命名、换库、补日志和优化性能。任务越小,测试失败后的定位成本越低,模型也越不容易把“顺手清理”扩散到无关文件。

# 先执行定向测试,快速确认目标函数的行为契约
pytest -q tests/test_phone.py -k normalize_phone

# 再查看差异,只允许检查本次任务涉及的文件
git diff -- phone.py tests/test_phone.py

请求里可以明确四个字段:现状症状、目标结果、不得改变的行为、验收命令。让 AI 生成测试时也要反向检查:新测试是否真的覆盖需求,还是只把当前实现重新抄了一遍。测试应当描述用户能观察到的结果,少依赖私有变量和具体实现细节。

用测试结果和代码差异做双重门禁

验收分三层更容易定位问题。第一层跑目标文件的定向测试,快速发现输入输出是否偏离;第二层跑完整回归,确认公共接口和相邻功能没有被破坏;第三层检查 git diff --stat、文件列表和关键差异,确认没有新增依赖、配置变更或无关重构。

检查项通过条件失败后的判断
定向单元测试目标行为与边界用例通过先修正实现或补清需求
完整回归原有测试不出现新增失败排查公共契约是否被改动
git diff文件、依赖和差异仍在预算内撤回越界改动,缩小请求
AI 生成代码通过定向测试、完整回归和 git diff 双重门禁的关系示意图
图2:测试结果与 git diff 双重门禁示意图,只有行为和范围同时满足约束才接受生成代码。

“测试全绿”不等于“可以合并”。如果模型顺便改了配置文件,或者把一个小函数拆成整套新依赖,即使现有测试通过,也应该按范围越界处理。反过来,diff 很小但边界测试失败,也不能因为改动看起来简单就接受。

失败时先缩小问题,再让 AI 重试

遇到失败,先把原因分成三类:测试失败说明行为不满足;差异越界说明任务边界没有守住;测试与需求都不清楚,说明验收标准需要补充。撤掉越界文件后,再把失败用例、期望结果和允许修改的单个符号重新发给 AI。不要把整段失败输出和一堆新要求混在一次请求里。

对高风险模块,还可以把单元测试结果接入提交检查,并要求人工看一遍依赖变化、异常处理和权限边界。GitHub 官方关于审查 AI 生成代码的建议也强调先运行自动化测试和静态分析,再结合项目上下文、依赖和安全风险做人工判断;这说明测试是起点,不是免检通行证。

常见问题

单元测试越多,AI 生成代码就越安全吗?

不一定。测试只能覆盖已写出的场景,不能自动发现遗漏需求、危险依赖或范围外的配置改动。测试数量应服务于关键行为和边界,而不是追求堆叠用例。

只检查 git diff,不跑完整测试可以吗?

不建议。小范围差异也可能破坏公共接口;至少先跑目标测试,再按项目成本安排完整回归,二者分别约束行为和影响面。

应该让 AI 先写测试还是先写实现?

对已有功能的修改,优先先确认并固定现有契约,再让 AI 改实现。对新功能,可以让 AI 提出测试草案,但必须由开发者确认边界后再把它作为验收标准。

收尾:把“生成”变成可回退的工程动作

AI 生成代码的效率来自缩短输入到候选实现的距离,可靠性则来自候选实现之后的约束。把目标函数、不变量、最小单元测试和 diff 预算绑定起来,每次只验收一个小任务,失败就回到清晰边界重新生成,才能让 AI 成为受控的实现助手,而不是未经审查的批量改动入口。

参考资料

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>