上周我接了个需求,要给一个内部工具写个文件差异对比模块------就是那种对比两个文本文件,然后高亮标出增删改的功能。说难不难,说简单吧,边界情况一堆:大文件怎么办、编码不一致怎么办、二进制文件要不要跳过。
我第一反应是直接开干。但转念一想,这不正好拿 PTC 模式试试水吗?
PTC 是 Plan-Test-Code 的缩写,翻译过来就是"先规划、再写测试、最后写代码"。听着是不是特别像 TDD(测试驱动开发)?说实话我第一次看到 PTC 的时候也觉得,这不就是 TDD 换个马甲嘛。但真正跑了一次之后,我发现这玩意儿跟 TDD 是两码事------TDD 是人写测试驱动人写代码,PTC 是人写测试驱动 AI 写代码。你定标准和验收条件,Agent 去干活,角色完全反过来了。
我先把需求拆了拆:对比模块需要支持行级 diff、输出统一格式(类似 unified diff)、能处理大文件流式读取、还要区分二进制和文本文件。放到 PTC 的 Plan 阶段,就是让 Agent 先出一份实施方案。
有意思的是,Agent 给的 Plan 比我预想的细得多。它不光列了要做哪些函数,还把每个函数的输入输出、异常处理、边界条件都写在了测试用例里。比如"当两个文件完全相同时返回空 diff""当文件不存在时抛出 FileNotFoundError"------我本来只想了三个测试场景,它一口气列了十几个。
你别说,看到这份 Plan 的时候我有点心虚。因为我自己写代码,通常是想好主干逻辑就开始敲了,边写边修边界。但 PTC 这种"先写测试再写代码"的流程,逼着你在一开始就把所有可能出错的地方想清楚。这就像装修前先画施工图------你可以在图纸上改一百遍,但上了墙再改,成本就大了。
然后进入 Test 阶段。Agent 开始基于 Plan 自动生成测试用例。这里有个坑------我第一次跑 PTC 的时候,Agent 生成的测试代码依赖了它自己还没写的模块,结果测试跑不起来。搞了半天才明白,PTC 的 Test 阶段生成的不是"能独立运行的测试",而是"描述预期的测试骨架"。你得自己把骨架里的 mock(模拟对象)和 fixture(测试夹具)补全,让它能真正跑起来。
笑死,我当时还在想,不是说好 AI 帮我写测试吗,怎么还得我动手。后来想通了------测试的价值在于"你"对需求的理解是否正确。如果测试全是 AI 写的,你只是无脑说"好,通过",那跟没测有啥区别?PTC 的哲学是:人定义"正确",AI 负责"实现"。
补完测试骨架之后,我跑了一遍------全红。正常,因为还没写实现代码。
Code 阶段才是真正惊艳我的地方。Agent 拿到测试用例之后,开始逐个实现函数。每实现一个就跑一遍测试,红了就改,绿了就下一个。这个过程是自动进行的,你可以盯着终端看它怎么"自己跟自己较劲"。
我印象最深的是处理大文件那个场景。我写的测试用例要求:超过 100MB 的文件不能一次性读入内存,必须分块处理。Agent 第一次实现用的是 readlines(),直接读全部行------测试跑挂了。它自己看了错误信息,换成 readline() 逐行读,测试通过了。整个过程没人干预,它自己 Debug 自己改。
你想想,这跟让一个 junior 工程师干活有啥区别?你告诉他需求,他写代码,跑不通自己改。但 PTC 的 Agent 不会累、不会烦躁、不会"先这样吧回头再修"。我那个 diff 模块一共 7 个函数,从 Plan 到全部测试通过,大概花了 15 分钟。换我自己写,光写测试就得半小时,再写实现、调 bug,一个上午下不来。
当然,PTC 也不是万事大吉。诚实地说,有两个问题我到现在还没完全解决。
一个是测试本身的维护成本。当你的测试用例从十几个涨到几十个,每次改需求都得同步更新测试------这不光是 Agent 的事,你作为"定标准的人"也得跟着改。我那个 diff 模块后来加了忽略空白符的功能,结果有 7 个测试用例要调整。虽然不是不能接受,但确实比直接改代码多了一步。
另一个是复杂场景的测试覆盖。Agent 倾向于写"路径最优"的测试------正正常常输入、正正常常输出。那些刁钻的边界条件,比如并发写入、文件锁、权限拒绝,Agent 基本不会主动覆盖。你得自己补充这些"坏心眼"的测试用例。
所以我的感受是:PTC 不是把 TDD 自动化了,而是把 TDD 的"角色"重新分了工。你负责"坏心眼"------想那些刁钻的、不常见的、用户可能瞎操作的情况。Agent 负责"搬砖"------把正常的、可预期的、文档里写清楚的功能实现好。你们两个合起来,才算一个完整的小团队。
你觉得这种"人定标准、AI 实现"的协作方式,未来会不会成为主流?还是说最终我们还是会走到"AI 自己定标准、自己实现"那一步?