用 AI 为遗留 Python 代码补齐可执行单元测试
先让 AI 理解行为,而不是立刻写测试
遗留代码最棘手的地方通常不是缺少测试框架,而是业务规则藏在分支、默认值和历史兼容逻辑中。以下函数来自一个订单模块:它根据金额、会员等级和优惠码计算应付金额,但没有任何测试。
def final_price(amount, vip, coupon):
if amount <= 0:
return 0
discount = 0.9 if vip else 1
if coupon == 'SAVE10' and amount >= 100:
discount -= 0.1
return round(amount * discount, 2)
不要只把函数贴给模型并要求“生成测试”。先要求它列出可观察的行为、边界条件、可能存在的歧义,以及每条规则对应的输入组合。例如可使用这样的提示词:“只分析以下函数,不修改实现。列出决策表,覆盖零值、负值、门槛值、VIP 与优惠码组合;指出折扣叠加的计算方式。”
这一步能避免 AI 根据函数名臆测业务含义。对上例,决策表至少应包含:金额小于等于零返回零;非会员满 100 元使用 SAVE10 后为九折;VIP 满 100 元使用 SAVE10 后为八折;99.99 元即使有优惠码也不减价。最后一条尤其适合发现门槛判断被误写为大于等于 99 的回归问题。
把规则转换为 pytest 测试
确认规则后,再让 AI 只输出 pytest 文件内容,并明确要求测试名称描述业务意图、不得 mock 纯函数、每个断言只验证一个关键结果。得到的结果应接近下面这样:
import pytest
from pricing import final_price
@pytest.mark.parametrize(('amount', 'vip', 'coupon', 'expected'), [
(0, False, None, 0),
(-1, True, 'SAVE10', 0),
(99.99, False, 'SAVE10', 99.99),
(100, False, 'SAVE10', 90.0),
(100, True, 'SAVE10', 80.0),
(100, True, None, 90.0),
])
def test_final_price_rules(amount, vip, coupon, expected):
assert final_price(amount, vip, coupon) == expected
运行 pytest -q 后,不要因为全部通过就直接合并。AI 生成的是基于当前实现的候选测试,可能把错误行为也固化下来。应把每个 expected 与产品规则、调用方行为或历史订单数据核对;如果“VIP 加优惠码是否允许叠加”没有明确依据,应先标为待确认,而不是让模型自行决定。
用失败测试定位旧代码风险
接着让 AI 扩展测试,但限定目标是发现风险而非追求覆盖率:“补充浮点精度、非法 coupon 类型和金额为 100 附近的测试;对没有明确契约的情形使用 xfail,并解释原因。” 这样可以将已确认规则与需要产品决策的行为分开。对包含数据库、HTTP 或时间依赖的遗留模块,应先用依赖注入或 pytest monkeypatch 隔离外部系统,再要求 AI 为真实边界生成测试;不要把联网、真实写库的测试误当作单元测试。
用 59API 控制持续补测成本
测试补齐往往需要多轮:分析函数、生成初稿、根据失败日志修正,再审查边界。59API 提供 Claude Opus、Sonnet、Haiku、Fable 与 GPT 模型的按量付费中转,使用原生官方质量模型,并兼容 Claude Code、Codex 和 OpenAI SDK。开发时可将 API 基址配置为 https://api.59api.com,把密钥放入环境变量,再按 59API 的兼容配置选择模型标识。
实践上可先用较低成本模型批量整理函数和测试矩阵,再把复杂状态机、并发逻辑或测试失败日志交给更强模型复核。这样既保留人工对业务契约的最终判断,也避免为大量重复测试分析付出过高成本。需要长期为旧项目补测试时,可以注册 59API 试用按量调用,并结合其推荐返利降低团队后续使用成本。
Prêt à commencer ?
Connectez Claude et GPT en quelques minutes aux prix les plus bas, sans bridage. Inscrivez-vous pour votre clé API.
Inscription gratuite